개념
- 클래스 안에 클래스가 들어갈 수 있다. 이러한 클래스를 Nested Class라고 한다.
- 한 곳에서만 사용되는 클래스를 논리적으로 묶어서 처리할 필요가 있을 때
- 캡슐화가 필요할 때(내부 구현을 감추고 싶을 때)
- 소스의 가독성과 유지보수성을 높이고 싶을 때
종류
- Static Nested class (static 키워드가 붙음)
- inner class (static 없음)
- Local inner class
- Anonymous inner class : 내부 익명 클래스
예제 : Static Nested Class
- 내부 클래스는 외부 클래스의 private 변수도 접근이 가능하지만, static nested class를 그렇게는 사용할 수 없다.
- static 아닌 변수를 static class에서 사용할 수 없으므로.
public class OuterOfStatic {
static class StaticNested {
private int value = 0;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
public static void main(String[] args) {
Main main = new Main();
main.makeStaticNestedObject();
}
public void makeStaticNestedObject() {
OuterOfStatic.StaticNested staticNested = new OuterOfStatic.StaticNested();
staticNested.setValue(3);
}
- 왜 사용하는가?
- 학교를 관리하는 School, 대학교를 관리하는 University가 있다고 가정하면, Student 클래스가 어느쪽에 속해있는지 불명확.
- 이럴때 School 밑에 static class Student, University 밑에 static class Student 만들어두면 용도가 명확해진다.
- 또한 School.Student 클래스는 School 클래스에 만들었기 때문에 University 클래스에서 사용 불가
예제 : 내부 클래스
public class OuterOfInner {
class Inner {
private int value = 0;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
}
public static void main(String[] args) {
Main main = new Main();
main.makeInnerObject();
}
public void makeInnerObject() {
OuterOfInner outer = new OuterOfInner();
OuterOfInner.Inner inner = new Inner();
inner.setValue(3);
}
- 객체를 생성해서 사용하는 것은 비슷하지만, 객체를 생성하는 방법에 차이가 있다.
- Inner 클래스 객체를 생성하기 전 Inner 감싸고 있는 Outer 클래스의 객체를 먼저 생성한 후 만들어내야 한다.
- 더 복잡하지만 이렇게 쓰는 이유는 캡슐화 때문이다.
- 하나의 클래스 내부에서 어떤 공통작업을 수행하는 클래스가 필요한데, 다른 클래스에서는 해당 클래스가 전혀 필요 없을 때 사용
- GUI 관련된 개발 시에 많이 사용한다. (리스너 처리)
예제 : 익명 클래스
public class MagicButton {
public MagicButton() {
}
private EventListener eventListener;
public void setEventListener(EventListener eventListener) {
this.eventListener = eventListener;
}
public void onClickProcess() {
if (eventListener != null) {
eventListener.onClick();
}
}
}
public interface EventListener {
public void onClick();
}
- 실제 사용시 아래처럼 익명 클래스를 활용하면 Listener 클래스를 생성할 필요 없이 사용 가능
public void setButtonListenerAnonymous() {
MagicButton button = new MagicButton();
button.setListener(new EventListener() {
public void onClick() {
System.out.println("Magic Button Clicked");
}
});
button.onClickProcess();
}
- 대신 클래스 이름도, 객체 이름도 없기 때문에 다른 클래스나 메소드에서는 참조할 수 없어서 아래처럼 객체를 생성한 후 사용해줘야 한다.
public void setButtonListenerAnonymousObject() {
MagicButton button = new MagicButton();
EventListener listener = new EventListener() {
@Override
public void onClick() {
System.out.println("Magic Button Clicked");
}
};
button.setEventListener(listener);
button.onClickProcess();
}
- 익명 클래스의 장점이 무엇이 있을까?
- 개발자가 클래스를 만들고, 호출하면 메모리에 올라간다. (클래스 많이 만들수록 메모리 많이 필요, 시작 시 시간도 많이 소요)
- 따라서, 이렇게 간단한 방법으로 객체를 만들 수 있도록 해놓았다.
기타 사항
* Inner Class나 익명 클래스는 모두 다른 클래스에서 재사용할 일이 없을 때 만들어야 한다.
* Nested Class가 Outer Class 변수들 중 참조 가능한 변수들
- static nested class : outer class의 static 변수만 참조 가능
- inner, anonymous : public, protected, default, private, static 다 참조 가능
* Outer Class 가 참조 가능한 Nested Class의 변수들
- 각 클래스의 객체를 생성하고 나서는 참조 가능(private 까지도)