728x90

package innerclass;
class A {
int i = 10;
}
class B {
void method() {
A a = new A();
System.out.println(a.i);
}
}
// B 클래스는 A 클래스의 외부 클래스라서 A 클래스의 멤버를 사용하려면 객체를 생성해야 했다.
package innerclass;
class Outer {
int a = 10;
class Inner {
int b = 100;
int c = 200;
public void method1() {
System.out.println(a);
}
}
}
// 내부 클래스에서는 외부 클래스 생성 없이 멤버를 그냥 사용할 수 있다
- 내부 클래스의 장점은 원래는 객체 끼리 멤버를 가져다 쓰려면 인스턴스를 사용한 다음 참조변수를 통해서 사용할 수 있는데, 내부 클래스는 객체를 생성하지 않고도 외부 클래스가 가진 멤버를 사용할 수 있다.
두 번째 장점은 Inner 클래스는 Outer 클래스에 담겨 있기 때문에 Outer 클래스 말고 다른 바깥 클래스는 Inner 클래스의 인스턴스를 생성할 수 없다.

- 내부 클래스 종류에 따라 살아있는 기간과 범위가 달라진다. 이것을 유효 범위라고 한다. 유효 범위는 변수와 같다.

package innerclass;
class OutClass {
int a = 10;
static int b = 20;
class InClass {
int i1 = a;
int i2 = b;
}
static class InStaticClass {
// int i1 = a; // 에러가 발생하는데, 그 이유는 static 클래스는 클래스 생성이 되기 이전
// 부터 로드되어 생성되는데, a 변수는 객체가 생성되어야 생성되는 변수이기 때문이다.
int i2 = b;
}
}
package innerclass;
class OutClass2 {
private int a = 10;
static int b = 20;
class InClass {
int i1 = a; // 외부 클래스의 private 멤버도 사용 가능
int i2 = b; // static 변수도 인스턴스 내부 클래스에서 당연히 사용 가능
}
static class InStaticClass {
int i2 = b; // static 내부 클래스에서는 외부 클래스의 static 변수만 사용 가능
}
void method() {
int i = 100;
class LocalInner { // 지역 내부 클래스
void innerMethod() {
// i = 200; // 오류가 발생한다. i 는 상수이기 때문이다.
// 오류 메시지를 보면 메소드 스코프 안에서 변수로 선언되었지만
// 메서드 안에 위치한 지역 내부 클래스에서는 상수로 사용해야 한다.
// 이런 이유는 메서드가 호출될 때 메모리에 생성되는데,
// 지역 내부 클래스는 new 를 사용하여 힙 메모리에 객체를 생성할 수 있다.
// new 를 사용한다는 것은 힙 메모리에 메소드의 멤버들이 생성된다는 것이다.
// 따라서 결국, 지역 내부 클래스와 메서드의 생애주기가 달라진다.
// 이런 오류를 막기 위해 지역 내부 클래스가 메서드의 멤버를 사용하려면
// 상수로 상정하고 사용해야만 한다.
}
}
}
}

- 익명 클래스의 제일 중요한 특징은 클래스 정의와 동시에 객체 생성을 할 수 있다.
- 익명 클래스는 한번 딱 쓰고 말 클래스에서 주로 사용한다.
- 예를 들어 위의 그림에 있는 코드를 보자.
runnerble 이라는 인터페이스가 있는데, 인터페이스를 구현한 다음 객체를 만들어서 사용해야 하는 것이 기존의 방식이다. 그런데, 익명 클래스를 사용하면 인터페이스를 상속 받는 클래스 정의와 해당 클래스 객체 생성을 동시에 할 수 있다는 장점이 생긴다. 위의 코드를 보면 인터페이스를 바로 상속받아 구현한 것을 볼 수 있는데 선언부는 객체 생성을 한 것을 볼 수 있다. 이것이 바로 익명 클래스의 형태이다. - 익명 클래스의 단점은 별도의 클래스 정의가 없기 때문에 일회성이다. 즉 다른 인스턴스를 만들어서 사용이 불가능하다. 그래서 딱 한번 쓰고 말 클래스에서 익명 클래스를 사용하게 된다.
package innerclass;
class RunnableChild implements Runnable {
@Override
public void run() {
System.out.println("running...");
}
}
// Runnable 은 jdk 에서 제공하는 기본 클래스 중 하나인데, 테스트를 위한 클래스이다.
// lang 패키지에 있는데, lang 패키지는 항상 자동 import 된다.
public class Ex5 {
public static void main(String[] args) {
Runnable child = new RunnableChild();
child.run();
// 우리가 흔히 사용하는 클래스의 객체를 만들어서 사용했다.
Runnable runnerble = new Runnable() {
@Override
public void run() {
System.out.println("running...");
}
};
// 익명 클래스를 사용해서 상속 받는 클래스 없이 바로 사용했다.
runnerble.run();
// 위 코드는 실행되지 않은 것을 확인할 수 있다.
}
}