[Java] 네스티드 클래스(Nested Class)와 이너 클래스(Inner Class)
네스티드 클래스(Nested Class)
📌 네스티드 클래스(Nested Class)
: 클래스 내에 정의된 클래스.
📌 외부 클래스(Outer Class)
: 네스티드 클래스(Nested Class)를 감싸는 클래스.
📌 네스티드 클래스(Nested Class) 종류
: static 선언 여부 기준.
① Static 네스티드 클래스
② Non-static 네스티드 클래스 = 이너 클래스(Inner Class)
📌 이너 클래스(Inner Class) 종류
: 클래스가 정의되는 위치, 특성에 따라 구분.
멤버 이너 클래스(Member Inner Class) | 인스턴스 변수, 인스턴스 메소드와 동일한 위치에 정의된 이너 클래스. |
로컬 이너 클래스(Local Inner Class) | 중괄호 내, 메소드 내에 정의된 이너 클래스. |
익명 이너 클래스(Anonymous Inner Class) | 클래스 이름이 존재하지 않는 이너 클래스. |
💡 '이너'를 빼고 '멤버 클래스', '로컬 클래스', '익명 클래스'라고 주로 부름.
Static 네스티드 클래스(Static Nested Class)
📌 Static 네스티드 클래스(Static Nested Class)
: static 선언된 네스티드 클래스.
📌 외부 클래스의 인스턴스와 상관없이 인스턴스 생성 가능.
외부 클래스의 인스턴스를 생성하지 않아도 Static 네스티드 클래스 인스턴스 생성 가능.
📌 외부 클래스의 이름을 포함하는 형태로 인스턴스 생성함.
→ [외부클래스].[내부클래스] [인스턴스명] = new [외부클래스].[내부클래스]
📌 외부 클래스의 static 멤버와 static 메소드에 접근 가능. (private도 접근 가능.)
외부 클래스의 인스턴스 변수와 인스턴스 메소드에 접근 불가능.
📄 StaticNestedClassTest.java
package nestedclass;
class Outer {
private static int num = 0;
static class Nested1 { // Static 네스티드 클래스.
void add(int n) {
num += n;
}
}
static class Nested2 { // Static 네스티드 클래스.
int get() {
return num;
}
}
}
public class StaticNestedClassTest {
public static void main(String[] args) {
Outer.Nested1 nst1 = new Outer.Nested1();
nst1.add(10);
Outer.Nested2 nst2 = new Outer.Nested2();
System.out.println(nst2.get()); // 10
}
}
멤버 이너 클래스(Member Inner Class)
📌 멤버 이너 클래스(Member Inner Class)
: 인스턴스 변수, 인스턴스 메소드와 동일한 위치에 정의된 이너 클래스.
📌 외부 클래스의 인스턴스 변수에 접근 가능. (private도 접근 가능.)
📌 멤버 클래스의 인스턴스는 외부 클래스의 인스턴스에 종속적임.
→ 외부 클래스 인스턴스 없이 멤버 클래스 인스턴스 생성 불가능.
📄 MemberClassTest.java
package innerclass;
class Outer {
private static int num = 0;
class Member { // 멤버 클래스.
void add(int n) { num += n; }
int get() { return num; }
}
}
public class MemberClassTest {
public static void main(String[] args) {
Outer o1 = new Outer();
Outer o2 = new Outer();
// o1 기반의 두 인스턴스 생성.
Outer.Member o1m1 = o1.new Member();
Outer.Member o1m2 = o1.new Member();
// o2 기반의 두 인스턴스 생성.
Outer.Member o2m1 = o2.new Member();
Outer.Member o2m2 = o2.new Member();
o1m1.add(10);
System.out.println(o1m2.get()); // 10
o2m1.add(20);
System.out.println(o2m2.get()); // 30
}
}
📌 클래스의 정의를 감춰야 할 때 사용.
📌 멤버 클래스가 private으로 선언되면, 멤버 클래스를 감싸는 클래스 내에서만 인스턴스 생성 가능.
📌 클래스 정의가 감춰지면 getPrinter 메소드가 반환하는 인스턴스가 다른 클래스의 인스턴스로 변경되어도, Papers 클래스 외부 코드를 수정하지 않아도 됨.
📄 MemberClassTest2.java
package innerclass;
interface Printable {
void print();
}
class Papers {
private String str;
public Papers(String s) { str = s; }
public Printable getPrinter() {
return new Printer(); // 멤버 클래스 인스턴스 생성 및 반환.
}
private class Printer implements Printable { // 멤버 클래스.
public void print() {
System.out.println(str);
}
}
}
public class MemberClassTest2 {
public static void main(String[] args) {
Papers p = new Papers("Hello:)");
Printable prn = p.getPrinter();
prn.print(); // Hello:)
}
}
+ 추가 설명
- 멤버 클래스가 private으로 선언되면, 멤버 클래스를 감싸는 클래스 내에서만 인스턴스 생성 가능.
→ Printable prn = p.getPrinter(); 과 같은 방식으로 인스턴스 참조.
- Paper 클래스 외부에서는 getPrinter 메소드가 어떤 인스턴스의 참조 값을 반환하는 지 알 수 없음.
Printable의 참조 변수로 참조 할 수 있다는 것만 알 수 있음.
→ 클래스 정의가 감춰진 상황.
- 클래스 정의가 감춰지면 getPrinter 메소드가 반환하는 인스턴스가 다른 클래스의 인스턴스로 변경되어도,
Papers 클래스 외부 코드를 수정하지 않아도 됨.
로컬 이너 클래스(Local Inner Class)
📌 로컬 이너 클래스(Local Inner Class)
: 중괄호 내, 메소드 내에 정의된 클래스.
📌 메소드 내에 클래스를 정의하면, 해당 메소드 내에서만 인스턴스 생성 가능.
→ 멤버 클래스보다 클래스를 더 깊이 특정 블록 안으로 감출 수 있음.
📄 Local ClassTest.java
package innerclass;
interface Printable {
void print();
}
class Papers {
private String str;
public Papers(String s) { str = s; }
public Printable getPrinter() {
class Printer implements Printable { // 로컬 클래스.
public void print() {
System.out.println(str);
}
}
return new Printer(); // 로컬 클래스 인스턴스 생성 및 반환.
}
}
public class LocalClassTest {
public static void main(String[] args) {
Papers p = new Papers("HELLO:)");
Printable prn = p.getPrinter();
prn.print(); // HELLO:)
}
}
익명 이너 클래스(Anonymous Inner Class)
📌 익명 이너 클래스(Anonymous Inner Class)
: 클래스 이름이 존재하지 않는 클래스.
📌 클래스의 정의와 인스턴스 생성을 하나로 묶을 수 있음.
📄 AnonymousClassTest.java
package innerclass;
interface Printable {
void print();
}
class Papers {
private String str;
public Papers(String s) { str = s; }
public Printable getPrinter() {
return new Printable() { // 익명 클래스 정의 및 인스턴스 생성.
public void print() {
System.out.println(str);
}
};
}
}
public class AnonymousClassTest {
public static void main(String[] args) {
Papers p = new Papers("HIIIIIII:)");
Printable prn = p.getPrinter();
prn.print(); // HIIIIIII:)
}
}