본문 바로가기
언어/Java

Java 기본 9 - 중첩 클래스/중첩 인터페이스/익명 클래스

by 넬준 2021. 11. 10.

중첩 클래스

특정 클래스와 관계를 맺을 경우는 관계 클래스를 클래스 내부에 선언하는 것이 좋다.

 

두 클래스(Outer, Inner)의 멤버들을 서로 쉽게 접근할 수 있다.

한 클래스(A)에서만 쓰이는 클래스(B)의 경우,

클래스(B)를 클래스(A)에 내장하도록 하는 것이 가독성, 유지보수 측면 모두에서 좋다.

즉, 외부에는 불필요한 클래스를 감춤으로써 코드의 복잡성을 줄일 수 있다. (캡슐화)

 

1) 멤버 클래스

1-1) 인스턴스 멤버 클래스

- 외부 클래스 객체를 생성한 후 내부 클래스 객체를 생성하여 사용

- 인스턴스가 생성되어야만 접근할 수 있기 때문에 static member 선언 불가

 

class Outer {
	class Inner {...}
}

//외부클래스 객체 생성, 컴파일 시 Outer.class
Outer outer = new Outer(); 
//그 후 내부클래스 객체 생성, 컴파일 시 Outer $ Inner.class
Outer.Inner  inner = outer.new Inner();

 

1-2) 정적 멤버 클래스

- 외부 객체를 생성하지 않아도 중첩 클래스를 생성할 수 있다.

- class에 붙는 static 키워드는 외부 클래스 객체 생성없이 내부 클래스 객체를 생성할 수 있음을 의미한다.

- https://johngrib.github.io/wiki/java-inner-class-may-be-static/#fnref:JOS-24

 

class Outer {
	static class Inner {...}
}

//외부 클래스 객체 생성없이 내부 클래스 객체 생성
//컴파일 시 Ounter $ Inner.class
Outer.Inner inner = new Outer.Inner();

 

2) 로컬 클래스

- 메소드 내에 선언한 중첩 클래스

- 메소드가 실행될 때만 생성하고, 사용할 수 있기 때문에 접근 제한자 및 static을 붙일 수 없다.

- 주로 비동기 처리를 위해 스레드 객체를 만들 때 사용한다.

 

class A {
	void method() {
    	class B {...}
        
        B b = new B();
        b.field = xx;
        b.get();
    }//method() end
}

//메소드 내부에서만 생성, 사용 가능하다
//컴파일 시 A $1 B.class

- 로컬 클래스에서 사용된, 메소드의 매개 변수와 로컬 변수는 모두 final 특성을 갖는다 (Java 8이후)

  -> 로컬 클래스 객체는 메소드 실행이 끝나도 heap 메모리에 남아 있어 계속 사용될 수 있지만, 매개 변수나 로컬 변수는 메소드 실행이 끝나면 stack 메모리에서 사라지기 때문에 로컬 클래스 객체에서 이를 사용할 경우 문제가 있다. 따라서 final 특성을 부여해 값이 한 번 정해지면 더 이상 바뀌지 않게끔 한 것이다.

 

** 중첩 클래스에서의 this 키워드는 중첩 클래스 본인의 객체 참조!

   외부 클래스의 객체를 참조하기 위해선 '외부 클래스명.this'로 사용해야 한다.

 

 

중첩 인터페이스

외부 클래스와 깊은 관계를 가진 구현 클래스를 만들기 위해서 사용

주로 UI 프로그래밍에서 이벤트 처리 목적으로 많이 활용

 

익명 클래스

- 클래스의 선언(정의) + 객체 생성을 동시에 하기 때문에 한 번만 사용되고,

  오직 하나의 인스턴스만을 생성할 수 있는 일회용 클래스

- 상속 + 내부클래스 (or 구현 + 내부클래스) -> 1회용 오버라이딩

- 한 번만 사용할 클래스를 여러 개 만드는 것은 비효율적이므로 익명 클래스로 구현

- 특정 구현 부분만 따로 사용하거나, 부분적으로 기능을 일시적으로만 변경할 때 보통 사용

 

public class Parent {
	void parentMethod() {}
}

public class A {
	//익명 자식 클래스 객체
	Parent aField = new Parent() {
		int childField;
		void childMethod() {}
		@Override
		void parentMethod() {
			childField = 3;
			childMethod();
		}
	};
	void aMethod() {
		aField.childField = 3; //컴파일 오류
		aField.childMethod(); //컴파일 오류
		aField.parentMethod(); //오버라이딩한 메소드가 호출
	}
}

 

- 익명 자식 클래스에서 정의된 필드와 메소드는 외부에선 접근할 수 없고, 내부에서만 사용할 수 있다.

  -> 여기서 aField는 Parent클래스 인스턴스가 아닌 Parent클래스를 상속받은 클래스의 인스턴스를 참조한다.

      (부모 클래스로 자동형변환, 다형성)

      따라서 부모클래스에서 선언한 필드와 메소드에만 접근할 수 있다.

      또는 해당 익명 자식 클래스에서 오버라이딩한 부모클래스의 메소드가 있다면

      익명 자식 클래스의 오버라이딩한 메소드가 호출된다.

 

'언어 > Java' 카테고리의 다른 글

자바 Queue에서 비슷한 메서드  (0) 2021.11.25
Java 기본 10 - 상속  (0) 2021.11.11
for-each문과 for문의 차이  (0) 2021.11.03
싱글톤 Singleton  (0) 2021.10.20
Java 기본 6 - 추상클래스  (0) 2021.05.24

댓글