Java/Java

[Java] 네스티드 클래스(Nested Class)와 이너 클래스(Inner Class)

기록하는_사람 2022. 10. 20. 21:37

네스티드 클래스(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:)
	}

}