내부 클래스¶
클래스 안에 클래스가 들어갈 수도 있구나¶
클래스 안의 클래스¶
Nested 클래스 필요성¶
- 한 곳에서만 사용되는 클래스를 논리적으로 묶어서 처리하고 싶을 때
- 캡슐화(encapsulation)가 필요할 때, 예를 들면 A라는 클래스의 멤버들을 B라는 클래스만 접근하게 하고 싶을 때 B라는 클래스를 A 클래스에 숨기는 기능을 할 수 있다.
- 소스의 가독성과 유지 보수를 효율적으로 하기 위해
Static nested 클래스의 특징¶
package c.inner;
class OuterOfStatic {
public OuterOfStatic() {
}
private static class StaticNested {
private int val = 0;
public StaticNested() {
System.out.println("Nested static class");
}
public int getValue() {
new OuterOfStatic();
return val;
}
public void setValue(int val) {
this.val = val;
}
}
}
StaticNested 클래스 객체 사용하는 방법을 알아보자.
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());
}
}
감싸고 있는 클래스 OuterOfStatic 이름 뒤에 점을 찍고 static 클래스 이름을 쓰고 객체를 만든다. 객체가 만들어진 후에 사용하는 방법은 일반 클래스와 같다.
내부 클래와 익명 클래스¶
package c.inner;
public class OuterOfInner {
class Inner {
private int val =0;
public int getValue() {
return val;
}
public void setValue(int val) {
this.val = val;
}
}
}
내부 클래스(inner class)를 사용하는 방법을 알아보자.
package c.inner;
public class NestedSample {
public void makeInnerObject() {
OuterOfInner outer = new OuterOfInner();
OuterOfInner.Inner inner = outer.new Inner();
inner.setValue(3);
System.out.println(inner.getValue());
}
public static void main(String[] args) {
NestedSample sample = new NestedSample();
sample.makeInnerObject();
}
}
Inner
클래스의 객체를 생성하기 전에 먼저 Inner
클래스를 포함하고 있는 OuterOfInner
클래스의 객체를 만들어야 한다. 그리고 그 객체를 통해서 outer.new
라는 예약어를 통해서 Inner
클래스의 객체를 만들어 낼 수 있다.
익명 클래스(anonymous class)¶
GUI(Graphic User Interface)에서 리스너(Listener)를 처리할 때 익명클래스를 많이 이용한다. 리스너란 키보드를 눌렀을 때 이벤트(Event)가 발생하는데 그러한 이벤트를 기다리고 있다가 발생되면 처리하는 클래스이다.
package c.inner;
public class MagicButton {
private EventListener listener;
public MagicButton() {
}
public void setListener(EventListener listener) {
this.listener = listener;
}
public void onClickProcess() {
if (listener != null) {
listener.onClick();
} else {
System.out.println("should set listener");
}
}
}
EventListener 인터페이스는 다음과 같다.
package c.inner;
public interface EventListener {
public void onClick();
}
클래스를 적용해 보자. 버튼을 누르는 과정을 모의실험해본다. onClickProcess()메소드는 실제 클래스에서는 만들지 않는다. 버튼을 클릭하는 행위를 대신하기 위해 만들어진 임시 메소드이다.
package c.inner;
public class NestedSample {
//중간 생략
public void setButtonListener() {
MagicButton button = new MagicButton();
button.setListener(???);
button.onClickProcess();
}
}
???안에 넣어야 할 리스너를 다음과 같이 클래스를 만들어서 넣을 수 있다.
package c.inner;
public class NestedSample {
//중간 생략
class MagicButtonListener implements EventListener {
public void onClick() {
System.out.println("Magic Button Clicked!!!");
}
}
}
다음으로 setButtonListener() 안에 EventListener의 객체를 생성해서 넣어준다.
package c.inner;
public class NestedSample {
//중간 생략
public void setButtonListener() {
MagicButton button = new MagicButton();
MagicButtonListener listener = new MagicButtonListener();
button.setListener(listener);
button.onClickProcess();
}
}
위와 같이 리스너를 내부 클래스로 만들어 사용할 수도 있지만 익명 클래스로 만들어서 사용할 수 있다. 익명 클래스를 사용할 때는 다른 곳에서 필요로하지 않을 때 사용한다. 즉 전용으로 사용하고자 할 때 사용하면 된다.
package c.inner;
public class NestedSample {
//중간 생략
public void setButtonListener() {
MagicButton button = new MagicButton();
// MagicButtonListener listener = new MagicButtonListener();
// button.setListener(listener);
button.setListener(new EventListener() {
public void onClick() {
System.out.println("Magic button clicked !!!");
}
});
button.onClickProcess();
}
}
setListener() 메소드 안에 EventListener를 새로 생성하면서 동시에 onClick()메소드를 구현하고 있는 것을 알 수 있다. 새로 생성된 클래스는 이름을 지정하지 않고 사용하기 때문에 익명 클래스라고 한다. 익명 클래스는 이름이 없기 때문에 다른 곳에서 참조를 할 수 없다. 만약 다른 곳에서 같은 객체를 재사용하려면 다음과 같이 사용한다.
package c.inner;
public class NestedSample {
//중간 생략
public void setButtonListener() {
MagicButton button = new MagicButton();
// MagicButtonListener listener = new MagicButtonListener();
// button.setListener(listener);
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;
}
};
}
}
Nested static 클래스 안에서는 static 변수만 참조할 수 있다.