내부 클래스란 클래스를 클래스 안에 선언하는 것이다. 이는 클래스의 멤버변수로 클래스의 참조변수를 갖는 것과는 다르다.
내부 클래스의 종류
내부 클래스 종류 | 설명 |
인스턴스 클래스(Instance Class) | 멤버변수 필드에 위치하며 위부 클래스와 관련된 작업에만 사용 |
스태틱 클래스(Static Class) | 멤버변수 필드에 위치하며 static멤버나 static메서드에 관련된 작업에 사용된다. |
지역 클래스(Local Class) | 외부 클래스의 메서드나 초기화 블록안에 위치한다. 해당 블록 내에서만 사용이 가능하다. |
익명 클래스(Anonymous Class) | 클래스의 선언과 객체의 생성을 동시에 하는 1회용 클래스이다. |
아래와 같은 방식은 내부 클래스의 한 종류로 중첩클래스 또는 인스턴스클래스 라고 한다.
public class InnerClassTest{ // 외부 클래스
private int a = 10;
public class InnerClass{ // 내부 클래스
private int b = a + 10;
public int getB() {
return b;
}
}
public int getA() {
return a;
}
public static void main(String[] args) {
InnerClassTest classTest = new InnerClassTest();
System.out.println(classTest.getA()); // 10
InnerClassTest.InnerClass ic = classTest.new InnerClass(); // classTest인스턴스에 내부클래스 생성
System.out.println(ic.getB()); // 20
}
}
inner class의 접근제어자는 멤버변수와 마찬가지로 public, protected, default, private 등이 가능하다. (멤버변수의 접근제어자와 동일)
Static Class
static class는 내부 클래스의 한 종류이며 static키워드가 붙은 내부 클래스를 의미한다. static클래스에서 외부 클래스의 멤버에 접글할 때에는 외부클래스의 객체를 생성한 뒤에 접글을 해야 하며, 내부클래스 중에서 static멤버를 가질 수 있는 것은 static내부클래스뿐이다.
※final static은 상수로 취급한다.
public class InnerClassTest{ // 외부 클래스
private int a;
public static int b;
static { b++; }
InnerClass staticCalssresult1;
{ staticCalssresult1 = new InnerClass(); }
static class InnerClass{ // static class
public static int staticvalue;
static { staticvalue = b + 1; }
public void method() {
System.out.println("static클래스의 메서드입니다.");
}
}
public static void main(String[] args) {
InnerClassTest classTest = new InnerClassTest();
System.out.println(InnerClassTest.b);
System.out.println(InnerClassTest.InnerClass.staticvalue);
// static 내부 클래스는 외부 클래스를 객체화 하지 않고도 바로 객체화가 가능하다.
// 외부클래스이름.내부클래스이름 이 타입이 된다.
InnerClassTest.InnerClass ic = new InnerClassTest.InnerClass();
ic.method();
classTest.staticCalssresult1.method();
}
}
Local Class
public class InnerClassTest{ // 외부 클래스
public void method() { // local class
int localval1 = 10; // 값이 변경되 않는 한 상수로 취급
final int localval2 = 20;
// localval1 = 10000; // 이 주석을 풀면 int ivOflocalClass1 = localval1;이 문장에 오류가 방생
class LocalClass{ // class선언 해당 메서드 내부에서만 사용
final static int localClassStatic = 1000;
// JDK1.8부터는 변수이지만 값이 바뀌지 않으면 상수로 취급한다.
int ivOflocalClass1 = localval1; // method의 스택프레임이 삭제되면 지역변수도 소멸되는데 이 시점에도 LocalClass의 인스턴스는가 소멸된 지역변수를 참조하려는 문제점이 발생
int ivOflocalClass2 = localval2; // 상수는 constant pool에 저장되기 때문에 stack frame이 소멸되어도 인트턴스에서 참조가 가능!
public void localMethod() {
System.out.println("local class입니다.");
System.out.println("Local Class의 메서드입니다. 인스턴스변수들의 총합: " + (ivOflocalClass1 + ivOflocalClass2));
}
}
LocalClass lc = new LocalClass(); // 인스턴스 생성
lc.localMethod(); // method내에서 로컬클래스의 메서드 사용
System.out.println("Local Class의 상수사용" + LocalClass.localClassStatic); // 상수취급이니 사용가능
}
public static void main(String[] args) {
InnerClassTest classTest = new InnerClassTest();
classTest.method();
}
}
내부클래스의 메서드에서 this를 사용하면 내부 클래스를 가리키고 외부클래스이름.this는 외부클래스를 가리킨다.
이름이 중복되는 변수를 this를 사용하지 않고 사용하면 가장 가까운 변수를 나타낸다.
public class InnerClassTest{ // 외부 클래스
private int a = 10;
public class ThisTest{ // 내부 클래스
private int a = 20;
void method() {
int a = 30;
System.out.println(a); // 30
System.out.println(this.a); // 20
System.out.println(InnerClassTest.this.a); // 10
System.out.println(InnerClassTest.ThisTest.this.a); // 20
}
}
public static void main(String[] args) {
InnerClassTest classTest = new InnerClassTest();
InnerClassTest.ThisTest test = classTest.new ThisTest();
test.method();
}
}
Reference
- 자바의정석(남궁성지음, 도우출판)