Java/이론&문법

Nested Class

Bubbles 2023. 9. 15. 17:00

개념

  • 클래스 안에 클래스가 들어갈 수 있다. 이러한 클래스를 Nested Class라고 한다.
    • 한 곳에서만 사용되는 클래스를 논리적으로 묶어서 처리할 필요가 있을 때
    • 캡슐화가 필요할 때(내부 구현을 감추고 싶을 때)
    • 소스의 가독성과 유지보수성을 높이고 싶을 때

 

종류

  • Static Nested class (static 키워드가 붙음)
  • inner class (static 없음)
    • Local inner class
    • Anonymous inner class : 내부 익명 클래스

 

 

예제 : Static Nested Class

  • 내부 클래스는 외부 클래스의 private 변수도 접근이 가능하지만, static nested class를 그렇게는 사용할 수 없다.
    • static 아닌 변수를 static class에서 사용할 수 없으므로. 
public class OuterOfStatic {
    static class StaticNested {
        private int value = 0;
        public int getValue() {
            return value;
        }
        public void setValue(int value) {
            this.value = value;
        }
    }
}
  • 사용은 아래처럼 한다. 
public static void main(String[] args) {
	Main main = new Main();
	main.makeStaticNestedObject();
}
    
public void makeStaticNestedObject() {
	OuterOfStatic.StaticNested staticNested = new OuterOfStatic.StaticNested();
	staticNested.setValue(3);
}
  • 왜 사용하는가? 
    • 학교를 관리하는 School, 대학교를 관리하는 University가 있다고 가정하면, Student 클래스가 어느쪽에 속해있는지 불명확. 
    • 이럴때 School 밑에 static class Student, University 밑에 static class Student 만들어두면 용도가 명확해진다.
      • 또한 School.Student 클래스는 School 클래스에 만들었기 때문에 University 클래스에서 사용 불가 

예제 : 내부 클래스

public class OuterOfInner {
    class Inner {
        private int value = 0;
        public int getValue() {
            return value;
        }
        public void setValue(int value) {
            this.value = value;
        }
    }
}
  • 사용 예제
public static void main(String[] args) {
	Main main = new Main();
	main.makeInnerObject();
}
    
public void makeInnerObject() {
	OuterOfInner outer = new OuterOfInner();
	OuterOfInner.Inner inner = new Inner();
	inner.setValue(3);
}
  • 객체를 생성해서 사용하는 것은 비슷하지만, 객체를 생성하는 방법에 차이가 있다.
  • Inner 클래스 객체를 생성하기 전 Inner 감싸고 있는 Outer 클래스의 객체를 먼저 생성한 후 만들어내야 한다.
  • 더 복잡하지만 이렇게 쓰는 이유는 캡슐화 때문이다. 
    • 하나의 클래스 내부에서 어떤 공통작업을 수행하는 클래스가 필요한데, 다른 클래스에서는 해당 클래스가 전혀 필요 없을 때 사용
    • GUI 관련된 개발 시에 많이 사용한다. (리스너 처리) 

 


예제 : 익명 클래스 

  • 이름이 없는 클래스를 의미 
public class MagicButton {
    public MagicButton() {
        
    }
    
    private EventListener eventListener;
    public void setEventListener(EventListener eventListener) {
        this.eventListener = eventListener;
    }
    
    public void onClickProcess() {
        if (eventListener != null) {
            eventListener.onClick();
        }
    }
}

 

public interface EventListener {
    public void onClick();
}

 

  • 실제 사용시 아래처럼 익명 클래스를 활용하면 Listener 클래스를 생성할 필요 없이 사용 가능 
public void setButtonListenerAnonymous() {
    MagicButton button = new MagicButton();
    button.setListener(new EventListener() {
    	public void onClick() {
        	System.out.println("Magic Button Clicked");
        }
    });
    button.onClickProcess();
}

 

  • 대신 클래스 이름도, 객체 이름도 없기 때문에 다른 클래스나 메소드에서는 참조할 수 없어서 아래처럼 객체를 생성한 후 사용해줘야 한다. 
public void setButtonListenerAnonymousObject() {
    MagicButton button = new MagicButton();
    EventListener listener = new EventListener() {
        @Override
        public void onClick() {
            System.out.println("Magic Button Clicked");
        }
    };
    button.setEventListener(listener);
    button.onClickProcess();
}
  • 익명 클래스의 장점이 무엇이 있을까?
    • 개발자가 클래스를 만들고, 호출하면 메모리에 올라간다. (클래스 많이 만들수록 메모리 많이 필요, 시작 시 시간도 많이 소요)
    • 따라서, 이렇게 간단한 방법으로 객체를 만들 수 있도록 해놓았다.

 

기타 사항 

* Inner Class나 익명 클래스는 모두 다른 클래스에서 재사용할 일이 없을 때 만들어야 한다. 

* Nested Class가 Outer Class 변수들 중 참조 가능한 변수들

  • static nested class : outer class의 static 변수만 참조 가능 
  • inner, anonymous : public, protected, default, private, static 다 참조 가능 

* Outer Class 가 참조 가능한 Nested Class의 변수들

  • 각 클래스의 객체를 생성하고 나서는 참조 가능(private 까지도)