내부 클래스 Inner class
클래스 내에 선언된 클래스.
외부 클래스를 제외하고는 다른 클래스에서 잘 사용되지 않는 것이어야 한다.
종류
변수의 선언 위치에 따른 종류와 같다.
- 인스턴스 클래스 instance class
외부 클래스의 멤버변수 선언 위치에 선언.
외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용
- 스태틱 클래스 static class
외부 클래스의 멤버변수 선언 위치에 선언.
외부 클래스의 static 멤버, static 메서드에서 사용
- 지역 클래스 local class
외부 클래스의 메서드나 초기화 블럭 안에서 선언
선언된 영역 내부에서만 사용 가능
- 익명 클래스 anonymous class
클래스의 선언과 객체의 생성을 동시에 하는 이름 없는 클래스(일회용)
선언
선언 위치에 따른 변수의 유효범위와 접근성을 동일하게 갖는다.
public class Outer{
class InstanceInner {}
static class StaticInner {}
void method(){
class LocalInner {}
}
}
제어자와 접근성
엄연한 클래스므로, 제어자와 접근 제어자를 사용할 수 있다.
public class Outer{
private class InstanceInner {
int iv = 1;
// static int cv = 1; error
final static int CONSTANT = 1;
}
protected static class StaticInner {
int iv = 2;
static int cv = 2;
}
void method(){
class LocalInner {
int iv = 3;
// static int cv = 3; error
final static int CONSTANT = 3;
}
}
}
- 인스턴스 클래스와 스태틱 클래스
외부 클래스의 멤버변수와 같은 성질을 갖는다.
= 인스턴스 멤버와 static 멤버간의 규칙도 똑같이 적용된다.
- 스태틱 클래스
내부 클래스 중 유일하게 static 멤버를 가질 수 있다.
= 내부 클래스에 static 변수를 선언하려면 스태틱 클래스로 선언해야 한다.
- 지역 클래스
외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있다.
외부 클래스의 지역변수(지역 클래스가 포함된 메서드에 정의된 지역변수)는 final이 붙은 지역 변수(상수)만 접근 가능하다.
JDK1.8부터 지역 클래스에 접근하는 지역 변수는 자동으로 final이 붙는다.
- 상수(final과 static이 동시에 붙은 변수)는 모든 내부 클래스에서 정의 가능하다.
public class Outer{
class InstanceInner { }
static class StaticInner { }
InstanceInner iv = new InstanceInner();
static StaticInner cv = new StaticInner();
static void staticMethod(){
// InstanceInner obj1 = new InstanceInner(); error
Outer out = new Outer();
InstanceInner obj1 = out.new InstanceInner();
StaticInner obj2 = new StaticInner();
}
void instanceMethod(){
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// LocalInner lv = new LocalInner(); error
}
void method(){
class LocalInner { }
LocalInner lv = new LocalInner();
}
}
public class Outer{
private int outIv = 0;
static int outCv = 0;
class InstanceInner {
int iv1 = outIv;
int iv2 = outCv;
}
static class StaticInner {
// int iv = outIv; error
static int cv = outCv;
}
void method(){
int lv = 0;
final int LV = 0;
class LocalInner {
int iv1 = outIv;
int iv2 = outCv;
// int iv3 = lv; JDK1.8 이전: error
int iv4 = LV;
}
}
}
- 외부 클래스가 아닌 다른 클래스에서 내부 클래스에 접근할 경우
내부 클래스로 선언해서는 안 되는 클래스를 내부 클래스로 선언했다는 의미.
public class Outer{
class InstanceInner { }
static class StaticInner { }
}
public class Test {
public static void main(String[] args) {
Outer out = new Outer();
Outer.InstanceInner ii = out.new InstanceInner();
Outer.StaticInner si = new Outer.StaticInner();
}
}
- 내부 클래스와 외부 클래스에 선언된 변수의 이름이 같을 때
변수 앞에 'this' 또는 '외부 클래스.this'를 붙여서 서로 구별할 수 있다.
public class Outer{
int iv = 0;
class InstanceInner {
int iv = 1;
void method(){
int iv = 3;
System.out.println("iv: " + iv); // 3
System.out.println("this.iv: " + this.iv); // 1
System.out.println("Outer.this.iv: " + Outer.this.iv); // 0
}
}
}
익명 클래스 Anonymous class
클래스의 선언과 객체의 생성을 동시에 한다.
단 한번만 사용할 수 있고 오직 하나의 객체만을 생성할 수 있는 일회용 클래스.
오로지 단 하나의 클래스를 상속 받거나 단 하나의 인터페이스만을 구현할 수 있다.
new ClassName() {
void method() {}
}
new InterfaceName() {
void method() {}
}
public class Anony {
Object iv = new Object() {
void method();
};
static Object cv = new Object() {
void method();
};
void method(){
Object lv = new Object() {
void method();
};
}
}
참고 서적: 자바의 정석 3판