내부 클래스는 클래스 내에 선언된다는 점을 제외하고는 일반적인 클래스와 다르지 않다. 사용빈도가 높지 않으므로 내부 클래스의 기본 원리와 특징을 이해하는 정도까지만 학습해보자!
내부 클래스는 클래스 내에 선언된 클래스이다. 클래스에 다른 클래스를 선언하는 이유는 간단하다. 두 클래스가 서로 긴밀한 관계에 있기 때문이다.
한 클래스를 다른 클래스의 내부 클래스로 선언하면 두 클래스의 멤버들 간에 서로 쉽게 접근할 수 있다는 장점과 외부에는 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다는 장점을 얻을 수 있다.
내부 클래스의 장점
class A { class A { // 외부 클래스
... ...
} class B { // 내부 클래스
class B { -> ...
... }
} ...
}
이 때 내부 클래스인 B는 외부 클래스인 A를 제외하고는 다른 클래스에서 잘 사용되지 않아야 한다.
내부 클래스의 종류는 변수의 선언위치에 따른 종류와 같다. 내부 클래스는 마치 변수를 선언하는 것과 같은 위치에 선언할 수 있으며, 변수의 선언위치에 따라 인스턴스변수, 클래스 변수(static변수), 지역변수로 구분되는 것과 같이 내부 클래스도 선언위치에 따라 구분된다. 내부 클래스의 유효범위와 성질이 변수와 유사하므로 서로 비교해보면 이해하는데 많은 도움이 된다.
내부 클래스
1. 인스턴스 클래스 (instance class)
내부(멤버) 클래스의 예제
public class MemberClassDemo { // 외부 클래스
private String secret = "비공개";
String s = "외부";
class MemberClass { // 내부 클래스
String s = "내부";
public void show1() {
System.out.println("내부 클래스");
System.out.println(secret); // 외부 클래스의 private 멤버도 접근할 수 있다.
System.out.println(s); // 내부 클래스의 멤버 s를 의미한다.
System.out.println(MemberClassDemo.this.s); // 3행의 멤버 s를 의미한다.
}
// static String ssString = "정적 멤버 필드"; // 내부 클래스 내부에 정적 변수나 메서드를 포함할 수 없다.
// static void show2() {}
}
public static void main(String[] args) {
MemberClassDemo m = new MemberClassDemo();
// MemberCalssDemo 클래스의 멤버인 MemberClass 를 의미한다
MemberClassDemo.MemberClass m1 = m.new MemberClass(); // 내부 클래스 생성
System.out.println(m1.s);
m1.show1();
}
}
public class LocalClassDemo {
private String s1 = "외부";
void method() { // 메서드 안
int x = 1;
class LocalClass { // 지역 클래스
String s2 = "내부";
String s3 = s1; // 외부 클래스의 private 멤버도 접근할 수 있다.
public void show() {
System.out.println("지역 클래스");
// x = 2; // x는 method() 내부에 선언된 지역 변수 이다.
// 지역 변수는 사실상 final이므로 수정할 수 없다.
}
}
LocalClass lClass = new LocalClass();
System.out.println(lClass.s2);
lClass.show();
}
public static void main(String[] args) {
LocalClassDemo localClassDemo = new LocalClassDemo();
localClassDemo.method();
}
}
클래스 종류 별 예제
public class Chap_1_Java_Strart {
class InstanceInner {
}
static class StaticInner {
}
// 인스턴스 멤버 간에는 서로 직접 접근이 가능하다.
InstanceInner iv = new InstanceInner();
// static 멤버 간에는 서로 직접 접근이 가능하다.
static StaticInner cv = new StaticInner();
static void staticMethod() {
// static 멤버는 인스턴스멤버에 직접 접근할 수 없다.
// InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// 굳이 접근하려면 아래와 같이 객체를 생성해야 한다.
// 인스턴스클래스는 외부 클래스를 먼저 생성해야만 생성할 수 있다.
Chap_1_Java_Strart outer = new Chap_1_Java_Strart();
InstanceInner obj1 = outer.new InstanceInner();
}
void instanceMethod() {
// 인스턴스메서드에서는 인스턴스멤버와 static멤버 모두 접근 가능하다.
InstanceInner obj1 = new InstanceInner();
StaticInner obj2 = new StaticInner();
// 메서드 내에 지역적으로 선언된 내부 클래스는 외부에서 접근할 수 없다.
// LocalInner lv = new LocalInner();
}
void myMethod() {
class LocalInner {
}
LocalInner lv = new LocalInner();
}
}
class Icon {
interface Touchable { // 중첩 인터페이스이다.
void touch();
}
}
// Icon 클래스의 멤버 Touchable 인터페이스를 의미한다.
public class InnerInterfaceDemo implements Icon.Touchable {
@Override
public void touch() {
System.out.println("아이콘을 터치한다.");
}
public static void main(String[] args) {
Icon.Touchable btn = new InnerInterfaceDemo();
btn.touch();
}
}