Contents
Nested Class - in java
   Nov 18, 2022     9 min read

Nested 클래스

자바에서는 클래스안에 클래스가 들어갈 수 있다.

이것을 내부클래스(Nested class) 라고한다.

  • Nested 클래스가 존재하는 가장 큰 이유 : 코드를 간단하게 표현할 수 있기 때문이다.

Nested클래스는 자바 기반의 UI 처리를 할 때 사용자의 입력이나, 외부의 이벤트에 대한 처리를 하는 곳에서 많이 사용된다.

Untitled

  • 내부클래스를 알아가기
public classpublicClass{

}

class JustNotPublicClass{

}

위의 코드처럼 한다면 아래와 같이 나온다. 이것은 내부클래스가 아니다. 그냥 한 클래스일 뿐이다. 조심하자.

Untitled 1

Nested 클래스를 쓰는 이유

  • 한곳에서만 사용되는 클래스를 논리적으로 묶어서 처리할 필요가 있을 때 (static Nested클래스 사용하는 이유)
  • 캡슐화가 필요할 때 (inner 클래스를 사용하는 이유)
    • 예를 들면 A라는 클래스에 private 변수가 있다. 이 변수에 접근하고 싶은 B 클래스를 선언하고, B 클래스를 외부에 노출시키고 싶지 않을 경우 Nested 클래스를 사용한다.
  • 코드의 가독성과 유지보수성을 높이고 싶을 때 (둘 다)

static nested 클래스의 특징

내부 클래스는 감싸고 있는 외부 클래스의 어떤 변수도 접근할 수 있다.

하지만..

static nested 클래스는 불가능하다.

  • static nested 선언
public class OuterOfStatic {
    static class StaticNested{
        private int value = 0;
        public int getValue(){
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }
}
  1. OuterOfStatic이라는 클래스를 선언했다.
  2. OuterOfStatic 내부에 static으로 선언된 StaticNested라는 클래스가 선언되어 있다. 그 안에 선언된 메소드의 내용들은 간단하게 인스턴스 변수의 값을 지정하고, 조회하는 작업을 수행한다.
  • 위 클래스를 컴파일하면 어떤 결과가 나올까 ?
OuterOfStatic.class
OuterOfStatic$StaticNested.class

Nested 클래스는 감싸고 있는 클래스 이름뒤에 “$” 기호를 붙인 후 Nested 클래스 이름이 나온다.

Static Nested 클래스의 객체 생성 방법

  • OuterOfStatic 클래스
    • static Nested 클래스 : StaticNested
public class OuterOfStatic {
    static class StaticNested{
        private int value = 0;
        public int getValue(){
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }
}
public class NestedSample {
    public static void main(String[] args) {
        NestedSample sample = new NestedSample();
        sample.makeStaticNestedObject();
    }

    public void makeStaticNestedObject(){
        OuterOfStatic.StaticNested staticNested = new OuterOfStatic.StaticNested();
        staticNested.setValue(3);
        System.out.println(staticNested.getValue());
    }
}
OuterOfStatic.StaticNested staticNested = new OuterOfStatic.StaticNested();

static Nested 클래스를 만들었을 때 객체 생성

  • 감싸고있는클래스.Nested클래스

static Nested 클래스 활용

학교를 관리하는 School 이라는 클래스, 대학을 관리하는 University 라는 클래스가 있다.

이때 Student라는 클래스를 만들면 School의 학생인지 University의 학생인지가 불문명해진다.

이럴때 static Nested class 를 사용한다.

public class University{
    static class Student{
    }
}
public class School{
    static class Student{
    }
}

겉으로는 유사하지만 내부적으로 구현이 달라야할 때 static Nested 클래스를 사용한다.


내부 클래스와 익명 클래스

  • static 이 빠진 그냥 내부 클래스 예제
public class OuterOfInner {
    class Inner{
        private int value = 0;
        public int getValue(){
            return value;
        }

        public void setValue(int value){
            this.value = value;
        }
    }
}

Inner 클래스의 객체 생성하는 방법

  1. Inner 클래스를 감싸고 있는 OuterOfInner 클래스 객체부터 생성해야한다.
  2. outer로 Inner 클래스의 객체를 만들어 준다.
OuterOfInner outer = new OuterOfInner();
OuterOfInner.Inner inner = outer.new Inner();
  • 전체 코드
public class InnerSample {
    public static void main(String[] args) {
        InnerSample sample = new InnerSample();
        sample.makeInnerObject();
    }

    public void makeInnerObject(){
        OuterOfInner outer = new OuterOfInner();
        OuterOfInner.Inner inner = outer.new Inner();
        inner.setValue(3);
        System.out.println(inner.getValue());

    }
}

내부 클래스 활용

내부 클래스를 만드는 이유는 캡슐화 때문이다.

하나의 클래스에서 어떤 공통적인 작업을 수행하는 클래스가 필요한데 다른 클래스에서는 그 클래스가 전혀 필요가 없을 때 내부 클래스를 사용한다.

  • 내부 클래스는 GUI 관련 프로그램을 개발할 때 많이 사용된다.
    • listener, Event 등등

익명 클래스(Anonymous class)

익명 클래스는 말그대로 이름이 없는 클래스이다.

  • 익명 클래스를 알아보자.
public class MagicButton {
    public MagicButton(){}

    private EventListener listener;
    public void setListener(EventListener listener){
        this.listener = listener;
    }

    public void onClickProcess(){
        if (listener != null) {
            listener.onClick();
        }
    }
}
  • EventListener 인터페이스
public interface EventListener {
    public void onClick();
}
  • 클래스를 적용 하기 위해서 클래스 생성
public class AnonymousSample {
    public static void main(String[] args) {
        AnonymousSample sample = new AnonymousSample();
        sample.setButtonListener();
    }

    public void setButtonListener() {
        MagicButton button = new MagicButton();
	      button.setListener(                 );
        button.OnClickProcess();
    }
}
  • 빈칸에 무엇을 넣으면 좋을까 ?
button.setListener(                 );
  • MagicButtonListener 클래스 생성
public class MagicButtonListener implements EventListener{

    @Override
    public void onClick() {
        System.out.println("Magic Button Clicked !");
    }
}
  • AnonymousSample클래스 안에 setButtonListener() 메소드 추가
public  void setButtonListener() {
    MagicButton button = new MagicButton();
    MagicButtonListener listener = new MagicButtonListener();
    button.setListener(listener);
    button.onClickProcess();
}
  • setButtonListener()메소드에서 button.setListener() 안에 listener 추가
public void setButtonListener() {
    MagicButton button = new MagicButton();
    button.setListener(listener);
    button.OnClickProcess();
}
  • 위의 작업을 손쉽게 익명 클래스로 끝낼 수 있다. 편리하고 가독성이 확실히 좋다 .
public void setButtonListenerAnonymous(){
    MagicButton button = new MagicButton();
    button.setListener(new EventListener(){

     @Override
     public void onClick() {
        System.out.println("Magic Button Clicked !!!!");
     }
    });
    button.onClickProcess();
}

setListener() 메소드를 보게되면 new EventListener() 로 생성자를 호출한 후 바로 중괄호를 열었다.

그 중괄호 안에는 onClick()메소드를 구현한 후 중괄호를 닫았다.

이것이 익명클래스다.

클래스에는 이름이 없지만 onClick() 메소드가 구현되어 있다.

setListener() 메소드가 호출되어 onClick() 메소드가 호출될 필요가 있을 때 그 안에 구현되어 있는 내용들이 실행된다.

클래스의 이름도 없고, 객체 아름도 없기 때문에 다른 클래스나 메소드에서 참조할 수가 없다.

  • 만약 객체를 해당 클래스 내에서 재사용하려면 ?
public void setButtonListenerAnonymousObject(){
    MagicButton button = new MagicButton();
    EventListener listener = new EventListener(){
        @Override
        public void onClick() {
            System.out.println("Magic Button Clicked!!!!!!");
        }
    };
    button.setListener(listener);
    button.onClickProcess();

}

익명클래스를 사용하면 코드의 가독성이 좋아진다. 하지만 너무 많이 쓸 경우 독이 될 수가 있다.


Nested 클래스의 특징

참조 가능한 변수

  1. Static Nested Class
  2. Inner Class
  3. Anonymout class
public class NestedValueReference {
    public int publicInt = 0;
    protected int protectedInt = 1;
    int justInt = 2;
    private int privateInt = 3;
    static int staticInt = 4;

    static class StaticNested{
        public void setValue(){
            staticInt = 14;
        }
    }

    class Inner{
        public void setValue(){
            publicInt = 20;
            protectedInt = 21;
            justInt = 22;
            privateInt = 23;
            staticInt = 24;
        }
    }

    public void setValue(){
        EventListener listener = new EventListener(){
            public void onClick(){
                publicInt = 30;
                protectedInt = 31;
                justInt = 32;
                privateInt = 33;
                staticInt = 34;
            }
        };
    }
}

1️⃣첫 번째 Staic Nested 클래스

  • Static Nested 클래스에서 감싸고 있는 클래스의 static 변수만 참조 가능
    • Static Nested 클래스가 static으로 선언되어있기 때문에 부모 클래스(감싸고있는 클래스)에 static하지 않은 변수를 참조할 수 없다.

2️⃣두 번째 Inner 클래스

  • 내부 클래스는 감싸고 있는 클래스의 어떤 변수라도 참조 가능

3️⃣세 번째 Anonymous 클래스

  • 익명 클래스는 감싸고 있는 클래스의 어떤 변수라도 참조 가능

➡️감싸고 있는 클래스에서 Static Nested 클래스의 인스턴스 변수나 내부 클래스의 인스턴스 변수로의 접근은??

  • 결론 : 참조가능하다. 코드를 확인하자.
package main.Chapter16;

public class ReferenceAtNested {
    static class StaticNested{
        private int staticVestedInt = 99;
    }

    class Inner{
        private int innerValue = 100;
    }

    public void setValue(int value){
        StaticNested nested = new StaticNested();
        nested.staticVestedInt= value;
        Inner inner = new Inner();
        inner.innerValue = value;
    }
}

각 클래스의 객체를 생성한 후 그 값을 참조하는 것은 가능하다.

StaticNested nested = new StaticNested();
nested.staticVestedInt= value;

참고 문헌

  • 자바의 신

Nested 회고

Nested의 세가지를 정확히 파악한 것은 확실하다. 이제 활용할 때 의식하면서 사용해보자.

GUI 이런 곳에 많이 쓰인다고 하니깐 정말 간단한 게임을 만들어봐야겠다.

미사일 피하기, 스티브 워즈니악과 스티븐 잡스가 제작한 브레이크 타임을 만들어봐야겠다.

이제 기본적인 자바는 더 탄탄히 다져진 것 같다.