클래스 내에 선언하는 클래스로, 일반적인 클래스와 유사함
실제 사용 빈도는 낮은 편
클래스 내에 다른 클래스를 선언하는 이유는, 둘의 관계가 긴밀하기 때문
양쪽 멤버들에 서로 쉽게 접근 가능
외부에 불필요한 클래스를 감출 수 있음 (코드 복잡성 감소)
class A {
...
class B {
...
}
...
}
바깥쪽인 A
를 외부 클래스, 안쪽인 B
를 내부 클래스라고 부름
선언 위치에 따라 구분
구분 | 특징 |
인스턴스 클래스 (instance class) |
- 멤버변수 선언위치에 선언 - 인스턴스 멤버처럼 다뤄짐 |
스태틱 클래스 (static class) |
- 멤버변수 선언위치에 선언 - 스태틱 멤버처럼 다뤄짐 |
지역 클래스 (local class) |
- 메서드나 초기화 블럭 안에 선언 - 선언된 영역 내부에서만 사용 가능 |
익명 클래스 (anonymous class) |
- 클래스의 선언과 인스턴스 생성을 동시에 함 - 일회용 |
같은 위치에 선언된 변수와 동일한 스코프 및 접근성을 가짐
class Outer {
int instanceVar = 7;
static int classVar = 7;
void instanceMethod() {
int localVar = 7;
}
}
class Outer {
class InstanceClass {}
static class StaticClass {}
void instanceMethod() {
class LocalClass {}
}
}
내부 클래스는 외부 클래스의 멤버로 간주되어, 멤버에 사용할 수 있는 public
, protected
, private
같은 접근 제어자나 final
을 붙일 수 있음
그와 동시에 클래스이기도 하기 때문에 abstract
나 static
같은 제어자도 사용 가능함
단,
static
내부 클래스만static
멤버를 가질 수 있음대신
final static
은 상수이므로, 모든 내부 클래스에서 사용 가능
클래스의 멤버들에 대해 존재하는 다음 규칙은
인스턴스 멤버 → 같은 클래스 내의 static
멤버와 인스턴스 멤버 모두 직접 사용 가능
static
멤버 → 같은 클래스 내의 static
멤버 사용 가능. 인스턴스 멤버는 해당 클래스의 인스턴스 생성 없이는 사용 불가능
지역 멤버 → 같은 클래스 내의 static
멤버와 인스턴스 멤버 모두 직접 사용 가능
내부 클래스에 대해서도 동일하게 적용됨
인스턴스 클래스 → 외부 클래스의 static
멤버와 인스턴스 멤버 모두 직접 사용 가능
static
클래스 → 외부 클래스의 static
멤버 사용 가능. 인스턴스 멤버는 외부 클래스의 인스턴스 생성 없이는 사용 불가능
지역 클래스 → 같은 클래스 내의 static
멤버와 인스턴스 멤버 모두 직접 사용 가능.
단, 자신이 포함된 메서드에 존재하는 지역 변수를 사용할 때는 상수만 사용 가능
이유: 지역 클래스는 지역 변수를 참조할 때, 사실은 그 변수들의 사본을 만들어 사용하기 때문에 사본의 정확성을 위해 원본 지역변수의 값이 불변해야함
(
JDK
1.8부터는 지역 변수에 명시적으로final
을 안붙여도 초기화 이후에 값의 수정이 없는 변수면 상수로 간주함)
class Outer {
private int outerIV = 0;
static int outerCV = 0;
class InstanceInner {
int innerIV = outerIV;
int innverIV2 = outerCV;
} // 인스턴스 클래스에서 외부 클래스의 인스턴스 변수와 클래스 변수 모두 접근 가능
static class StaticInner {
// int staticInnerIV = outerIV; 스태틱 클래스에서는 외부 클래스의 인스턴스 변수 접근 불가
static int staticInnerCV = outerCV; // 클래스 변수는 접근 가능
}
void someMethod() {
int outerLV = 0; // 초기화 이후 값이 변하지 않으므로 상수 취급 (final 생략 가능)
int outerLV2 = 0;
...
outerLV2 = 0; // 초기화 이후 값이 변했으므로 상수가 아님
class LocalInner {
int localInnerIV = outerIV;
int localInnerIV2 = outerCV;
int localInnerIV3 = outerLV; // 지역 클래스는 상수만 접근 가능
// int localInnerIV4 = outerLV2; 상수가 아닌 경우는 접근 불가
}
}
}
외부 클래스와 내부 클래스에 선언된 변수명이 같을 때는
외부 클래스의 변수 → 외부클래스명.this.변수명
내부 클래스의 변수 → this.변수명
으로 구분함
선언과 인스턴스 생성을 동시에 함
이름이 없기 때문에 한 번만 사용되는 일회용 클래스
생성자 보유 불가
1개의 클래스만 상속받거나, 1개의 인터페이스만 구현할 수 있음
조상 클래스를 상속받거나 인터페이스를 구현할 때, 굳이 새 클래스를 만들지 않고 일회성 객체를 만드는 거라 보면 됨.
new 상속받을조상클래스명() {
...
}
// 또는
new 구현할인터페이스명() {
...
}
class Outer {
Object instanceVar = new Object() {
void method() {
...
}
}; // 인스턴스 익명 클래스
static Object classVar = new Object() {
void method() {
...
}
}; // 스태틱 익명 클래스
void outerMethod() {
Object localVar = new Object() {
void method() {
...
}
}; // 지역 익명 클래스
}
}