본문 바로가기

Language/JAVA

[JAVA]중첩/내부 클래스

해당 게시글의 내용은 '김영한의 실전 자바 - 중급편' 을 기반으로 작성되었으며, 제가 학습한 내용을 토대로 다시 작성하게 되었습니다.

중첩 클래스, 내부 클래스란?

클래스 안에 클래스를 중첩해놓은 클래스를 중첩 클래스(Nested Class)라고 합니다.

class(...){
   class(...){

   }
}

중첩 클래스의 분류

중첩 클래스는 크게 1. 정적 중첩 클래스2. 내부 클래스들(내부 클래스, 지역 클래스, 익명 클래스)로 나뉘어 집니다.

 

또한, 중첩 클래스를 선언하는 위치는 변수를 선언할 때의 위치와 동일합니다.

[중첩 클래스의 선언 위치]

class Outer{
	//정적 중첩 클래스 (static nested class)
	static class StaticNested {
		...
	}
	
	//내부 클래스
	class Inner {
		...
	}
}
  • 정적 중첩 클래스: 정적(static) 변수와 같은 위치
  • 내부 클래스: 인스턴스 변수와 같은 위치
  • 정적 중첩 클래스는 정적 변수와 같이 static이 붙어 있습니다.
  • 내부 클래스는 인스턴스 변수와 같이 static이 붙어있지 않습니다.
class Outer{
	public void process() {
		//지역 변수
		int localVar = 0;
		
		//지역 클래스
		class Local {...}
		
		Local local = new Local();
	}
}
  • 지역 클래스: 지역 변수와 같은 위치
  • 지역 클래스는 지역 변수와 같이 코드 블럭 안에서 클래스를 정의합니다.
  • 쉽게 말해 메서드 안에서 정의할 수 있는 클래스입니다.

위에서 우리는 정적 중첩 클래스와 내부 클래스로 분류하였습니다.

그렇다면, 중첩내부라는 단어에는 무슨 차이가 있을까요?

  • 중첩: 어떤 다른 것이 내부에 위치하거나 포함되는 구조적인 관계
  • 내부: 나의 내부에 있는 나를 구성하는 요소

쉽게 정리하자면, 중첩내 안에 있지만 내 것이 아닌것(=나와 관련이 없다.)을 의미하고, 내부는 나의 내부 안에서 나를 구성하는 요소(=나와 관련이 있다.)를 말합니다. 

 

 

 

용어 정리

  • 중첩 클래스: 정적 중첩 클래스 + 내부 클래스의 종류를 모두 합한 것.
  • 정적 중첩 클래스: 정적 중첩 클래스를 말합니다.
  • 내부 클래스들: 내부 클래스(Inner Class), 지역 클래스(Local Class), 익명 클래스(Anonymous Class)

 

중첩 클래스는 언제 사용하나요?

모든 중첩 클래스는 특정 클래스가 다른 하나의 클래스 안에서만 사용되거나, 두 클래스가 아주 긴밀히 연결되어 있는 특별한 경우에만 사용합니다. 

외부의 여러 클래스가 특정 중첩 클래스를 사용한다면 중첩 클래스로 만들어선 안됩니다.

 

 

 

중첩 클래스를 사용하는 이유

[논리적 그룹화]

특정 클래스가 다른 클래스 안에서만 사용되는 경우, 이러한 중첩 클래스가 논리적으로 더 그룹화됩니다. 또한, 패키지를 열었을 때 다른 곳에서 사용될 필요가 없는 중첩 클래스가 외부에 노출되지 않는 장점도 있습니다.

[캡슐화]

중첩 클래스는 바깥 클래스의 private 멤버의 접근할 수 있습니다. 이를 통해서 두 클래스를 더 긴밀하게 연결하고 불필요한 public 메서드를 제거할 수 있습니다.


정적 중첩 클래스

정적 중첩 클래스

package chapter08.nested;

public class NestedOuter {
    private static int outClassValue = 3;
    private int outInstanceValue = 2;

    static class Nested {
        private int nestedInstanceValue = 1;
        public void print(){
            //자신의 멤버의 접근
            System.out.println(nestedInstanceValue);

            //바깥 클래스의 인스턴스 멤버에 접근에는 할 수 없다.
            // System.out.println(outInstanceValue);

            // 바깥 클래스의 클래스 멤버에는 접근할 수 있다., private에도 접근이 가능합니다.
            System.out.println(outClassValue);
        }
    }
}
  • private 접근 제어자는 같은 클래스 안에 있을때만 접근이 가능합니다.
  • 정적 중첩 클래스는 바깥 클래스와 같은 클래스 내부에 선언되어 있습니다. 따라서, 정적 중첩 클래스는 바깥 클래스의 private 접근 제어자에 접근이 가능합니다.
package chapter08.nested;

public class NestedOuterMain {
    public static void main(String[] args) {
        //NestedOuter outer = new NestedOuter();
        NestedOuter.Nested nested = new NestedOuter.Nested();
        nested.print();

        System.out.println("nestedClass = "+nested.getClass());
    }
}

/*
[실행 결과]

1
3
nestedClass = class nested.nested.NestedOuter$Nested
*/
  • 정적 중첩 클래스는 new 바깥클래스.중첩클래스()로 생성할 수 있습니다.
  • 정적 중첩 클래스는 NestedOuter.Nested와 같이 바깥 클래스.중첩 클래스로 접근할 수 있습니다.
  • 여기서 new NestedOuter()의 인스턴스와 new NestedOuter.Nested()로 만든 정적 중첩 클래스의 인스턴스는 서로 아무런 관계가 없는 인스턴스입니다. (관계가 없기 때문에 정적 중첩 클래스의 인스턴스만 따로 생성해도 됩니다.)
static 인데, 정적 중첩 클래스도 인스턴스를 생성해야 하나요?
정적 중첩 클래스는 static으로 선언되었기 때문에 바깥 클래스의 인스턴스 없이도 생성할 수 있습니다.
하지만 여전히 new 키워드를 통해서 인스턴스를 생성해주어야 합니다. 즉, 정적 중첩 클래스의 인스턴스를 만들 때는 new 바깥클래스.중첩클래스() 형식으로 생성합니다. static이기 때문에 바깥 클래스의 인스턴스와는 독립적으로 존재할 수 있습니다.

 

Nested.print()를 살펴보면, 정적 중첩 클래스는 바깥 클래스의 정적 필드에는 접근할 수 있습니다. 하지만, 바깥 클래스가 만든 인스턴스 필드(outInstanceValue)에는 바로 접근할 수 없습니다. 왜냐하면 바깥 인스턴스에 대한 참조가 없기 때문입니다.

 

 

정리

정적 중첩 클래스와 바깥 클래스는 아무런 관련이 없습니다.

NestedOuter.outClassValue와 같이 정적 필드에 접근하는 것은 중첩 클래스가 아니어도 클래스명.정적 필드명으로 접근할 수 있습니다.

 

사실상 정적 중첩 클래스를 만들지 않고 아래와 같이 그냥 클래스 2개를 따로 만든 것과 같습니다.

class NestedOuter {
}

class Nested {
}

위 코드와 정적 중첩 클래스의 유일한 차이는 private 접근 제어자에 접근할 수 있다 정도입니다.

 

 

정적 중첩 클래스 활용

[활용 전]

package chapter08.nested.ex1;

public class NetworkMessage {
    private String content;

    public NetworkMessage(String content){
        this.content = content;
    }

    public void print(){
        System.out.println(content);
    }
}
package chapter08.nested.ex1;

public class Network {
    public void sendMessage(String text){
        NetworkMessage networkMessage = new NetworkMessage(text);
        networkMessage.print();
    }

}
package chapter08.nested.ex1;

public class NetwortkMain {
    public static void main(String[] args) {
        Network network = new Network();
        network.sendMessage("Hello Java");
    }
}
  • NetworkMain은 Network 클래스만 사용하고 NetworkMessage는 전혀 사용하고 있지 않습니다.
  • NetworkMessage는 오직 Network 내부에서만 사용합니다.
  • NetworkMainNetwork만 사용
  • NetworkNetworkMessage만 사용

[활용 후]

package chapter08.nested.ex2;

public class Network {
    public void sendMessage(String text){
        NetworkMessage networkMessage = new NetworkMessage(text);
        networkMessage.print();
    }

    private static class NetworkMessage {
        private String content;

        public NetworkMessage(String content){
            this.content = content;
        }

        public void print(){
            System.out.println(content);
        }
    }
}
public class NetworkMain {
    public static void main(String[] args) {
       Network network = new Network();
        network.sendMessage("Hello Java");
    }
}
  • NetworkMessage 클래스는 Network 클래스 안에서만 사용하기 때문에 중첩해서 만들었습니다.
  • NetworkMessage의 접근 제어자를 private로 설정했습니다. 따라서, 외부에서 NetworkMessage에 접근할 수 없습니다.

 

중첩 클래스의 접근

내 클래스에 포함된 중첩 클래스가 아닌 다른 곳의 중첩 클래스에 접근할 때는 바깥 클래스.중첩 클래스 방식으로 접근해야 합니다.

NestedOuter.Nested nested = new NestedOuter.Nested()

반면에 내 클래스에 포함된 중첩 클래스에 접근할 땐 바깥 클래스의 이름을 적지 않아도 됩니다.

public class Network {
	public void sendMessage(String text){
		NetworkMessage networkMessage = new NetworkMessgae(text);
	}
}

중첩 클래스의 용도는 자신이 소속된 바깥 클래스 안에서 사용되는 것인데, 이러한 용도와 다르게 자신이 소속된 바깥 클래스가 아닌 다른 외부에서 사용하고 있다면 이미 중첩 클래스의 용도와 맞지 않을 수 있습니다. 이 때는 중첩 클래스를 밖으로 빼는 것이 더 나은 선택입니다.


관련 포스팅

1. [JAVA]중첩/내부 클래스 (1/4)

2. [JAVA]내부 클래스 (2/4)

3. [JAVA]지역 클래스 (3/4)

4. [JAVA]익명 클래스 (4/4)

 

'Language > JAVA' 카테고리의 다른 글

[JAVA]지역 클래스(Local Class)  (0) 2024.09.24
[JAVA]내부 클래스(Inner Class)  (0) 2024.09.23
[JAVA]static 파헤치기  (0) 2024.09.23
[JAVA]Reflection??  (0) 2024.09.13
[JAVA]Thread란?  (0) 2024.09.09