1. 내부클래스
내부클래스는 클래스 내부에 선언된 클래스이다. 서로간에 긴밀한 관계를 가지는 클래스들에 대해서 한 클래스 내부에 다른 클래스를 선언함으로 내부에서 쉽게 접근하고, 외부에서는 해당 클래스에 대한 불필요한 접근을 감춤으로서 코드의 복잡성을 줄일 수 있다.
class A {
// 외부 클래스 A의 내부에 클래스 B를 선언한다.
class B {
...
}
}
2. 내부클래스의 종류와 특징
내부클래스의 종류는 변수의 선언위치에 따른 종류와 같다. 변수가 선언되는 위치에 따라 인스턴스 변수, 클래스 변수 (static 변수), 지역변수로 구분되는 것과 같이 내부클래스도 다음과 같이 구분된다.
내부 클래스 | 설명 |
인스턴스 클래스 | 외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 인스턴스 멤버처럼 다루어진다. 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 사용될 목적으로 선언된다. |
스태틱 클래스 | 외부 클래스의 멤버변수 선언 위치에 선언하며, 외부 클래스의 static 멤버처럼 다루어진다. 주로 외부 클래스의 static 멤버, 특히 static 메서드에서 사용될 목적으로 선언된다. |
지역 클래스 | 외부 클래스의 메서드나 초기화 블럭 안에 선언하며, 선언된 영역 내부에서만 사용될 수 있다. |
익명 클래스 | 클래스의 선언과 객체의 생성을 동시에 하는 이름없는 클래스 (일회용) |
3. 내부클래스의 선언
내부 클래스의 종류에 따라 선언되는 위치를 소스코드로 표현하면 다음과 같다.
class A {
class InstanceClass { ... }
static class StaticClass { ... }
void method() {
class LocalClass { ... }
}
}
내부 클래스는 멤버변수과 같이 선언되는 위치에 따라 종류가 달라지는데, 해당 클래스들의 유효범위와 접근성 또한 멤버변수와 같다.
4. 내부클래스의 제어자와 접근성
앞서말한 것과 같이 내부클래스는 멤버변수들과 같이 선언되는 위치에 따라 종류가 달라지며, 유효범위 (scope), 접근성 (accessibility) 또한 같다. 인스턴스 클래스와 스태틱 클래스 또한 인스턴스 멤버와 static 멤버와 같이 적용된다.
내부 클래스도 클래스이기 때문에 abstract나 final과 같은 제어자를 사용할 수 있을 뿐만 아니라 멤버변수들처럼 private, protected 접근제어자도 사용이 가능하다.
내부 클래스 중에 static 멤버는 스태틱 클래스만 가질 수 있다. 다만 final과 static이 동시에 붙은 변수는 상수로 인신되기 때문에 모든 내부 클래스에서 정의할 수 있다.
또한 인스턴스 클래스는 외부의 인스턴스 멤버들을 객체생성 없이 바로 사용할 수 있지만, 스태틱 클래스는 외부 클래스의 인스턴스 멤버를 객체 생성 없이 사용할 수 없다. 마찬가지로 인스턴스 클래스는 스태틱 클래스의 스태틱 멤버들을 객체생성없이 사용할 수 있지만, 스태틱 클래스에서는 인스턴스 클래스의 멤버들을 객체생성 없이 사용할 수 없다.
class OuterClass {
private int outerInstanceVar = 0;
static int outerClassVar = 0;
class InstanceClass {
// 인스턴스 클래스는 외부 클래스의 private 멤버도 접근 가능하다.
int var1 = outerInstanceVar;
int var2 = outerClassVar;
}
static class StaticClass {
// 스태틱 클래스는 외부 클래스의 인스턴스 멤버에 접근할 수 없다.
// int var1 = outerInstanceVar; // error 발생
// 스태틱 클래스는 외부 클래스의 스태틱 멤버에 접근할 수 있다.
static int var2 = outerClassVar;
}
void method() {
int localVar= 0;
final int localConstant = 0; // JDK1.8부터 final 생략 가능
class LocalClass {
int var1 = outerInstanceVar;
int var2 = outerClassVar;
// 외부 클래스의 지역변수는 final이 붙은 변수 - 상수만 접근 가능하다.
int var3 = localVar; // 기존에 error 발생하였으나, JDK1.8 부터 error 아님.
int var4 = localConstant;
}
}
}
인스턴스 클래스는 외부 클래스의 인스턴스 멤버이기 때문에 인스턴스 변수와 클래스 변수 모두 접근할 수 있다. 심지어 private 변수에도 접근이 가능하다.
스태틱 클래스는 외부 클래스의 static 멤버이기 때문에 외부 클래스의 인스턴스 멤버 (인스턴스 변수, 인스턴스 클래스)에 접근할 수 없다. 단지 static 멤버만 사용할 수 있다.
지역 클래스는 외부 클래스의 인스턴스 멤버와 static 멤버를 모두 사용할 수 있다. 또한 지역 클래스가 포함된 메서드에 정의된 지역변수도 사용할 수 있다. 단 final 이 붙은 지역변수만 가능한데, 그 이유는 메서드가 수행을 마쳐서 지역 변수가 소면된 시점에도 지역 클래스의 인스턴스가 소멸된 지역변수를 참조하려는 경우가 발생할 수 있기 때문에 이를 금지한다.
JDK1.8 부터는 지역 클래스에서 접근하는 지역 변수 앞에 final을 생략할 수 있게 바뀌었다. 대신 컴파일러가 자동으로 이를 붙여준다. 즉 편의상 final을 생략할 수 있게 한 것 일뿐 해당 변수의 값이 바뀌는 문장이 있으면 컴파일 에러가 발생한다.
내부클래스를 컴파일하면 '외부클래스명$내부클래스명.class' 형식으로 클래스 파일이 생성된다. 다만 서로 다른 메서드 내에서는 같은 이름의 지역변수를 사용하는 것이 가능한 것처럼, 지역내부 클래스는 다른 메서드에 같은 이름의 내부 클래스가 존재할 수 있기 때문에 내부 클래스명 앞에 숫자가 붙는다.
5. 익명 클래스 (anonymous class)
익명 클래스는 다른 내부 클래스들과는 달리 이름이 없다. 클래스의 선언과 객체 생성을 동시에 하기 때문에 단 한번만 사용될 수 있고, 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이다.
이름이 없기 때문에 생성자도 가질 수 없으며, 조상 클래스의 이름이나 구현하고자 하는 인터페이스의 이름을 사용해서 정의하기 때문에 하나의 클래스로 상속받는 동시에 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없다. 오로지 단 하나의 클래스를 상속받거나 단 하나의 인터페이스를 구현할 수 있다.
class OuterClass {
Object obj = new Object() {
void method() { ... }
};
static Object staticObj = new Object() {
void method() { ... }
};
void localMethod() {
Object var = new Object() {
void method() { ... }
};
}
}
익명 클래스는 위와 같은 방식으로 선언될 수 있다. 이 예제를 컴파일하면 다음과 같이 4개의 클래스 파일이 생긴다.
- OuterClass.class
- OuterClass$1.class
- OuterClass$2.class
- OuterClass$3.class
익명 클래스는 클래스 이름이 없기 때문에 숫자 뒤에 아무런 이름도 붙지 않는다.
'프로그래밍언어 > JAVA' 카테고리의 다른 글
[JAVA] java.lang (0) | 2021.12.15 |
---|---|
[JAVA] 예외처리 (Exception handling) (0) | 2021.12.07 |
[JAVA] 인터페이스 (Interface) (1) | 2021.11.23 |
[JAVA] 추상클래스 (abstract class) (0) | 2021.11.20 |
[JAVA] 다형성 (Polymorphism) (0) | 2021.11.19 |