본문 바로가기

프로그래밍/Java

클래스안의 클래스-2

반응형

해당 포스트의 작성 목적

앞서 내부 클래스를 공부했을때는 명확한 개념이나 쓰임새 등에 대해서 알지 못했다.

내부 클래스란 무엇이고, 이런 종류가 있다 정도만 훑고 이해했다.

이번 포스팅에서는 '그냥 내부클래스라는 개념이 있다' 정도의 지식에서 좀더 깊게 파고들어가, 내부클래스가 왜 사용되는지 실제로 코드로 작성,직접 체감하며 이해하고자 한다.

내부 클래스는 왜 사용하는가?

앞서 포스팅한 내용을 그대로 가져왔다.

  • 한 곳에서만 사용되는 클래스를 논리적으로 묶어서 처리할 필요가 있을때
  • 캡슐화가 필요할 때 (A클래스에 private변수를 선언, 이 변수에 접근하고 싶은 B클래스를 만들고 이 B클래스를 외부로 노출시키고 싶지 않을때) 즉, 내부구현을 감추고 싶을때 사용한다.
  • 소스의 가독성과 유지보수성을 높이고 싶을때

첫번째 이유가 StaticNested클래스를 사용하는 이유이고, 두번째가 inner클래스를 사용하는 이유이다.

 

세번째 이유는 어느정도 이해가 된다. 자바스크립트로 개발할때 onClick메소드에 로직을 다 담지 않고, 매개변수를 받아서 처리하는 메소드를 또 만들고는 했었다.

첫번째 이유도 세번째 이유와 비슷한 이유로, (한 화면에서 쓰이는 클릭 메소드는 그 화면에서만 쓰이는 경우가 많았다.... 내 경험으로는...) 어렴풋이 왜 써야할지 알겠으나, 그게 StaticNested클래스가 되야하는지는 잘 모르겠고, 두번째 이유는 전혀 감도 잡히지 않는다....

StaticNested클래스의 특징

내부클래스는 자신을 감싸고있는 외부 클래스의 어떤 변수도 접근이 가능하다. 심지어 private으로 선언된 변수조차, 그러나 StaticNested클래스를 그렇게 사용할 수는 없다. 왜냐하면 Static하기 때문에, Static자원들만 사용이 가능하다. Static Netsted 클래스를 컴파일 해보자

package e.inner;

public class OutofStatic {
    static class StaticNested{
        private int value=0;

        public int getValue() {
            return value;
        }
        public void setValue(int value) {
            this.value = value;
        }
    }
}
/*
컴파일 결과 생성된 파일들! 

2021-05-17  오후 03:20               472 OutofStatic$StaticNested.class
2021-05-17  오후 03:20               312 OutofStatic.class
2021-05-17  오후 03:19               280 OutofStatic.java
*/

내부클래스를 감싼 외부클래스의 java,class파일 외에,

외부클래스명$내부클래스명.class

로 된 파일이 컴파일 된것을 볼수있다. 저 클래스파일이 내부클래스 파일이다. 그럼, 이렇게 컴파일된 내부클래스는 어떻게 객체를 생성할 수 있을까??

package e.inner;

public class NestedSample {
    public static void main(String[] args){
        NestedSample ns = new NestedSample();
        ns.makeStaticNestedObject();
    }
    public void makeStaticNestedObject(){
        OutofStatic.StaticNested os = new OutofStatic.StaticNested();
        os.setValue(3);
        System.out.println(os.getValue());
    }
}

StaticNested클래스를 감싸고있는 외부클래스명 뒤에 .(점)을 찍어 객체를 생성할 수있으며, 이후 사용법은 일반적인 클래스와 동일하다.

앞서 말한 StaticNested의 쓰임새를 예를 들어 다시 설명해보겠다.

학교를 관리하는 School이라는 클래스를 만들고, 대학을 관리하는 University라는 클래스를 만들었을 때를 생각해보자. 이때 Student라는 클래스를 만들면 School의 학생인지, University의 학생인지 구분이 쉽지 않다. 이때 School 내에 Static Nested 클래스로 Student를 선언하면, School에서 사용되는 클래스임을 확실히 알 수 있다. 그래서 겉으로 보기에는 유사하지만, 내부적으로 구현이 달라야 할 떄 이처럼 Static Nested클래스를 사용하곤 한다.(해당 설명은 모든 Nested클래스에 해당되는 말과 비슷하다고 보여진다.. 왜 꼭 Static이어야 하는지는.... 나와있지 않다. 오히려 Static 자원밖에 쓰지 못하기 때문에 더 불리하지 않나?..)

내부클래스(Inner클래스)

앞서 살펴본 StaticNested클래스와 Inner클래스(내부클래스)는 Static의 유무만 차이가 나는것 처럼 보인다. 과연 실제로도 그럴까??? 다음의 코드를 통해 알아보자.

package e.inner;

public class OutofInner {
	class Inner{
		private int value = 0;
		public int getValue() {
			return value;
		}
		public void setValue(int value) {
			this.value = value;
		}
	}

}
package e.inner;

public class InnerSample {
	public static void main(String[] args) {
		InnerSample is = new InnerSample();
		is.makeInnerObject();
	}
	
	public void makeInnerObject() {
		OutofInner oi = new OutofInner();
		OutofInner.Inner in = oi.new Inner();
		in.setValue(10);
		System.out.println(in.getValue());
	}
}

StaticNested클래스와 객체를 생성하는 점이 다르다. StaticNested클래스와 다르게, Inner클래스를 감싸고 있는 외부클래스에 대한 객체를 먼저 생성해야하고, 그 생성된 외부클래스의 객체로부터 new 연산자를 통해 내부클래스의 객체를 생성할 수 있다. 이렇게 되면 내부클래스는 객체를 생성한 것 만으로도

외부클래스에 대한 참조가 생기므로, GC의 대상에서 벗어난다.

이를 유념하고 코딩할 수 있도록 하자. 이런 내부클래스를 만드는 이유는 캡슐화 때문이라고 했다.

하나의 클래스에서 공통의 작업을 수행

하는 클래스가 필요한데,

다른 클래스에서는 그 클래스가 전혀 필요없을 때

내부클래스를 사용한다.(자바에서는 주로 GUI관련 프로그램을 개발할때 쓰인다. 하나의 버튼을 눌렀을때 동작해야하는 작업은 대부분 상이하여 하나의 별도로 클래스를 만들기보다, 내부클래스를 만들어 쓰는것이 훨씬 편하며, 뒤에 나올 익명클래스는 더더욱 편하다.)

익명클래스(Anonymouse)

Java에서 익명클래스는 말그대로 이름이 없는 클래스를 말한다. 예제 코드를 통해서 이해해보도록 하자.

public void setButtonListener() {
		MagicButton mb= new MagicButton();
		mb.setListener(new EventListener () {
			public void onClick() {
				System.out.println("printed out");
			}
		});
		mb.onClickProcess();
	}

new EventListener() 연산자로 생성자 호출후,

클래스 이름없이

바로 중괄호를 열었다. 그후 onClick()이라는 메소드를 작성한 후 중괄호를 닫았다. 이렇게 생성된 객체를 setListener()를 통해 바로 이용이 가능하다. 단, 이럴경우 객체의 재상요이 불가능함으로, 다음과 같이 객체를 생성해서 재사용 할수도 있다.

public void setButtonListener() {
		MagicButton mb= new MagicButton();
		EventListener listener = new EventListener () {
			public void onClick() {
				System.out.println("printed out");
			}
		};
		mb.setListener(listener);
		mb.onClickProcess();
	}

그럼 이렇게 복잡하게 익명클래스를 생성하는 이유는 뭘까?... 그냥 내부클래스로 작성해도 될탠대...

익명클래스를 만들었을 때의 장점을 생각해보자. 클래스를 만들고, 그 클래스를 호출하면 메모리에 그 정보가 올라간다. 즉 클래스를 많이 만들수록 메모리에 올라가는 양이 많아진다. 그러나 익명클래스는 클래스 정보를 메모리에 올리지 않고도, 객체를 생성할 수 있다.

포스트를 작성하며 알게 된점

내부클래스들 (StaticNested, Inner, Anonymouse)의 객체 생성방법에 알게되었다.

그렇지만, StaticNested클래스가 아직도 왜 한곳에서만 사용되는 클래스를 논리적으로 묶을때 사용하는지는 모르겠다. Static한것과 관련이 있는건가?.. 사실 다른 내부클래스들도 똑같이 적용 할 수 있다고 생각하는데. 해당 의문점에 대한 궁금증을 풀어줄수 있는 자료를 아직 검색하지 못했다.

References

자바의신1

 

반응형

'프로그래밍 > Java' 카테고리의 다른 글

Annotation  (0) 2021.05.17
Static 변수의 메모리 해제-Weak/Soft Reference  (0) 2021.05.17
GC Log보는 방법  (0) 2021.05.13
클래스 안의 클래스-1  (0) 2021.05.13
JVM이란 무엇인가  (0) 2021.05.13