내부 클래스는 클래스 내에 선언되는 클래스입니다. 내부의 클래스가 외부 클래스와 연관관계가 깊으며, 다른 클래스에서 사용되지 않을 때 내부클래스를 사용하게됩니다.
내부 클래스의 구분은 변수의 선언에 따른 구분과 비슷하게 이루어집니다. 인스턴스 변수와 같이 선언하면 인스턴스 클래스, 스태틱 변수처럼 선언하면 스태틱 클래스, 블록 내에 선언하면 로컬 클래스입니다.
내부 클래스도 abstract
및 final
, 그리고 private
, protected
와 같은 접근 제어자를 사용할 수 있습니다. 다만 static
멤버는 스태틱 클래스만 가질 수 있습니다. 다만 final
과 static
이 모두 사용된 상수는 모든 내부 클래스에서 정의가 가능합니다.또한 내부 클래스와 외부클래스는 서로의 멤버가 private
제어자로 선언되어 있어도 접근이 가능합니다.
멤버 변수의 메서드 접근처럼, 스태틱 클래스는 인스턴스 멤버에 접근할 수 없습니다. 또 스태틱 클래스는 외부 클래스의 인스턴스 없이 직접 객체를 선언할 수 있습니다. 이와 같은 규칙들은 모두 클래스 - 스태틱 멤버 간의 규칙을 따릅니다.
class OuterClass{
private static int oStaticInt;
private int oInt;
public OuterClass() {
System.out.println("I'm O");
//각각의 이너클래스의 private에 접근가능
//이너클래스의 스태틱 멤버접근 가능
A.aStaticInt = oStaticInt;
// 인스턴스가 없는 A 클래스멤버 접근 불가
oInt = A.aInt;
}
static class A {
private static int aStaticInt;
private int aInt;
public A() {
System.out.println("I'm A");
oStaticInt = aStaticInt;
//인스턴스가 생성되지 않은 OuterClass의 멤버에 접근 불가
oInt = aInt;
}
}
class B{
private int bInt;
//Non-Static 클래스에 static 멤버 선언 불가
private static int bStaticInt;
public B() {
A.aStaticInt = bInt;
oInt = bInt;
}
}
}
public class InnerStaticClassTest {
public static void main(String[] args) {
OuterClass o = new OuterClass();
//외부 클래스 인스턴스 없이 접근 가능
OuterClass.A a = new OuterClass.A();
//외부 클래스의 인스턴스를 통해서만 접근 가능
OuterClass.B b = o.new B();
}
}
final
이 없는 인스턴스 멤버에도 접근이 가능** 자바에서 스태틱 키워드가 의미하는 바를 정확히 이해해야 합니다. 스태틱 메서드, 변수, 클래스 모두 상위에 존재하는 클래스의 인스턴스를 필요로 하지 않습니다. 스태틱 클래스는 인스턴스를 만들 수 있느냐 없느냐가 아닌 스태틱 키워드 관점에서 클래스 로딩 시점에 접근할 수 있는 지 없는 지를 판단하는 것입니다. **
외부 클래스의 메서드가 기능이 많아 기능별로 분류하거나, 선언하려는 클래스가 외부 클래스에 종속적일경우 사용합니다.
내부클래스는 대부분 외부클래스에 종속적으로 사용되므로 외부에서는 접근할 수 없도록 private
제어자를 사용하고 내부클래스의 인스턴스를 생성할 필요가 없을 경우 static
제어자를 사용합니다.
어떤 클래스가 다른 클래스에 종속적이라면 각각 선언했을 때 캡슐화된 클래스들 간의 멤버 변수 접근 간에 getter
및 setter
를 사용해야하며 각각은 서로에 의존적일 수 있습니다. 이럴경우 내부클래스로 선언하여 종속적인 클래스에 대해서 캡슐화를 할 수 있습니다. 이 경우 내부 클래스와 외부 클래스는 서로의 멤버 접근에 자유로우므로 getter
및 setter
를 사용하지 않고도 서로의 멤버에 접근하게 할 수 있습니다.
익명클래스는 이름이 없는 클래스입니다. 즉 클래스의 선언과 생성을 단 한번하고 사라지게 됩니다. 생성자도 존재하지 않으며 클래스 상속 또는 인터페이스 구현체의 메서드를 재정의한 인스턴스를 단 한번 사용하기 위해 선언합니다.
new SuperClass(){
@Override
public method(){}
}
new Interface(){
@Override
public method(){}
}
이름이 없으므로 슈퍼클래스 혹은 인터페이스의 이름으로 객체를 생성합니다. 오버라이딩할 메서드를 생성과 동시에 재정의해서 사용합니다.
JDK 1.8 이후로는 람다식이 추가되어 익명클래스 대신에 람다식을 통해 구현할 수 있습니다.
참고 : 자바의 정석 1권
내부 정적 클래스 참고 : https://stackoverflow.com/questions/7486012/static-classes-in-java