본문 바로가기
Backend/Java

[자바의 신] 16장

by unknownomad 2022. 7. 25.

16장 - 클래스 안에 클래스가 들어갈 수도 있구나


클래스 안의 클래스, Nested 클래스

  • 코드 간단 표현 가능
  • 자바 기반의 UI 처리 시 사용자 입력 및 외부 이벤트 처리하는 곳에서 많이 사용
package c.inner;

public class PublicClass {
}

class JustNotPublicClass {
}
  • 파일 이름 : public한 클래스 이름 따서 정의해야함(컴파일 에러 방지)

Nested 클래스 사용 이유

  • 한곳에서만 사용되는 클래스를 논리적으로 묶어 처리할 때 = Static nested 클래스 사용 이유
  • 캡슐화 필요할 때 = 내부 구현 감추고 싶을 때 = 내부(inner) 클래스 사용 이유
  • 소스 가독성과 유지보수성 높이고 싶을 때
Static nested 클래스 내부 클래스
내부 클래스처럼 접근 불가 감싸고 있는 외부 클래스의 어떤 변수도 접근 가능
private으로 선언된 변수도 접근 가능

  • Nested 클래스 예시
package c.inner;

public class OuterOfStatic {
    static class StaticNested {
        private int value = 0;
        
        public int getValue() {
            return value;
        }
        
        public void setValue(int value) {
            this.value = value;
        }
    }
}
//생성되는 클래스 목록
OuterOfStatic.class
OuterOfStatic$StaticNested.class

  • Static nested 클래스 예시
package c.inner;

public class NestedSample {
    public static void main(String[] args) {
        NestedSample sample = new NestedSample();
        sample.makeStaticNestedObject();
    }
    
    public void makeStaticNestedObject() {
        OuterOfStatic.StaticNested staticNested = new OuterOfStatic.StaticNested();
        staticNested.setValue(3);
        System.out.println(staticNested.getValue());
    }
}

  • 내부 클래스 예시
package c.inner;

public class OuterOfInner {
    class Inner {
        private int value = 0;
        
        public int getValue() {
            return value;
        }
        
        public void setValue(int value) {
            this.value = value;
        }
    }
}
package c.inner;

public class InnerSample {
    public static void main(String[] args) {
        InnerSample sample = new InnerSample();
        sample.makeInnerObject();
    }
    
    public void makeInnerObject() {
        OuterOfInner outer = new OuterOfInner();
        OuterOfInner.Inner inner = outer.new Inner();
        inner.setValue(3);
        System.out.println(inner.getValue());
    }
}
  • Inner 클래스의 객체 생성 전에는 먼저 Inner 클래스를 감싸고 있는 OuterOfInner 라는 클래스의 객체 생성해야 함
  • 캡슐화에 유용
  • 하나의 클래스에 공통 작업 수행하는 클래스가 필요한데 다른 클래스에서는 그 클래스가 필요 없는 경우, 이런 내부 클래스 만들어 사용
  • GUI 관련 프로그램 개발 시 많이 활용

GUI

  • Graphic User Interface (사용자 화면용 애플리케이션)
  • GUI에서 내부 클래스들이 많이 사용되는 경우 : 리스너(Listener) 처리 시
  • 사용자가 버튼 클릭하거나 키보드 입력 시 이벤트(Event) 발생
  • 어떤 버튼 눌릴 때 해야 하는 작업 정의하기 위해 내부 클래스 만들어 사용
  • But 하나의 애플리케이션에서 어떤 버튼 눌릴 때 수행해야 하는 작업은 대부분 상이함
  • ➡ 하나의 별도 클래스 만들어 사용하는 것보단 내부 클래스 만드는 게 훨씬 편함
  • ➡ 내부 클래스보다 더 간단한 방법 = 익명 클래스

익명 클래스

  • Anonymous class
  • 이름 없는 클래스
package c.inner;

public class MagicButton {
    public MagicButton() {
    }
    
    private EventListener listener;
    public void setListener(EventListener listener) {
        this.listener = listener;
    }
    
    public void onClickProcess() {
        if(listener != null) {
            listener.onClick();
        }
    }
}
package c.inner;

public interface EventListener {
    public void onClick();
}
class MagicButtonListener implements EventListener {
    public void onClick() {
        System.out.println("Magic Button Clicked");
    }
}
package c.inner;

public class AnonymousSample {
    public static void main(String[] args) {
        AnonymousSample sample = new AnonymousSample();
        sample.setButtonListener();
    }
    
    public void setButtonListener() {
        MagicButton button = new MagicButton();
        MagicButtonListener listener = new MagicButtonListener();
        button.setListener(listener);
        button.onClickProcess();
    }
}
  • 화면 클릭 시 MagicButtonListener에 있는 onClick() 메서드 수행
    (실제 GUI에서는 onClickProcess() 메서드 실행 x)

  • 익명 클래스 예시
public void setButtonListenerAnonymous() {
    MagicButton button = new MagicButton();
    button.setListener(new EventListener() {
        public void onClick() {
            System.out.println("Magic Button Clicked");
        }
    });
    button.onClickProcess();
}
  • setListener() 메서드 호출하는 과정 내에 익명 클래스가 있기에 소괄호와 세미콜론 주의
  • 익명 클래스는 클래스 이름도 없고 객체 이름도 없기에 다른 클래스나 메서드에서 참조 불가
  • 해당 클래스 내에서 익명 클래스 재사용하려면 하기처럼 객체 생성해야
public void setButtonListenerAnonymousObject() {
    MagicButton button = new MagicButton();
    
    EventListener listener = new EventListener() {
        public void onClick() {
            System.out.println("Magic Button Clicked");
        }
    };
    button.setListener(listener);
    button.onClickProcess();
}


익명 클래스 장점

  • 클래스 만들고 호출 시 해당 정보는 메모리에 올라감
    = 클래스 많이 만들수록 많은 메모리 필요
    = 애플리케이션 시작 시 더 많은 시간 소요
  • 자바는 익명 클래스 같은 방법으로 객체 생성해 메모리 소모 줄일 수 있음


익명 클래스와 내부 클래스

  • 둘 다 다른 클래스에서 재사용할 일이 없을 때 만들어야함

  • Nested 클래스 특징
package c.inner;

public class NestedValueReference {
    public int publicInt = 0;
    protected int protectedInt = 1;
    int justInt = 2;
    private int privateInt = 3;
    static int staticInt = 4;
    
    static class StaticNested {
        public void setValue() {
            staticInt = 14;
        }
    }
    
    class Inner {
        public void setValue() {
            publicInt = 20;
            protectedInt = 21;
            justInt = 22;
            privateInt = 23;
            staticInt = 24;
        }
    }
    
    public void setValue() {
        EventListener listener = new EventListener() {
            public void onClick() {
                publicInt = 30;
                protectedInt = 31;
                justInt = 32;
                privateInt = 33;
                staticInt = 34;
            }
        };
    }
}
Static nested 클래스 내부 클래스와 익명 클래스
Static nested 클래스에서는 감싸고 있는 클래스의 static 변수만 참조 가능
Static nested 클래스가 static으로 선언되어 있기에 부모 클래스의 static하지 않은 변수는 참조 불가
만약 참조 시 컴파일 에러 발생
감싸고 있는 클래스의 어떤 변수라도 참조 가능

  • 반대로의 참조 예시
package c.inner;

public class ReferenceAtNested {
    static class StaticNested {
        private int staticNestedInt = 99;
    }
    
    class Inner {
        private int innerValue = 100;
    }
    
    public void setValue(int value) {
        StaticNested nested = new StaticNested();
        nested.staticNestedInt = value;
        Inner inner = new Inner();
        inner.innerValue = value;
    }
}
  • 각 클래스 객체 생성 후 그 값 참조 가능(해당 값이 private해도 접근 가능)

'Backend > Java' 카테고리의 다른 글

[자바의 신] 18장  (0) 2022.07.26
[자바의 신] 17장  (0) 2022.07.25
[Java] String ➡ Long 타입으로 형변환  (0) 2022.03.30
[Java] 정수 최대값, 최소값 구하기  (0) 2022.03.28
[Java] int와 Integer 비교  (0) 2022.03.21

댓글