ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 내부 클래스
    java/Class.Interface.Method 2021. 8. 29. 14:46

    코틀린 내부 클래스

    https://hellose7.tistory.com/119

     

    [kotlin] Nested Class

    [Java/Nested Class] - [Java] 내부 클래스 [Java] 내부 클래스 non-static 내부 클래스 인스턴스 생성법 반드시 외부 클래스 인스턴스를 통해 인스턴스를 생성해야한다. class Outer { class Inner { } } public..

    hellose7.tistory.com

     

    내부 클래스란 클래스 안에 선언된 클래스를 의미한다.

     

    http://www.tcpschool.com/java/java_usingClass_innerClass

     

    보통 non-static 내부 클래스를 Inner 클래스라고 부르고, static 내부 클래스를 static nested 클래스라고 부른다.


    non-static  내부 클래스

     

    • 인스턴스 생성법

     

    반드시 외부 클래스 인스턴스를 통해 인스턴스를 생성해야한다.

    class Outer {
    	class Inner {
    	}
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    		Outer outer = new Outer();
    		System.out.println(outer.toString());
    		
    		Outer.Inner inner = outer.new Inner(); 
    		System.out.println(inner.toString());
    	}
    }


    • 외부클래스명.this

     

    non static 내부 클래스의 인스턴스가 생성될시에는 외부 클래스의 인스턴스가 항상 존재한다. 

    그렇기 때문에 내부 클래스의 인스턴스를 사용할 수 있는 곳(생성자,멤버변수메서드)에서는 외부 클래스의 인스턴스를 나타내는 외부클래스.this 를 사용할 수 있다.

    class Outer {
    	class Inner {
    		public void printOuter() {
    			System.out.println(Outer.this);
    		}
    
    		public void printThis() {
    			System.out.println(this);
    			// = System.out.println(Inner.this);
    		}
    	}
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    		Outer outer = new Outer();
    		System.out.println(outer.toString());
    
    		Outer.Inner inner = outer.new Inner();
    		inner.printOuter();
    		
    	}
    }

     

     

    this 대신 인스턴스 멤버를 직접 참조하는 것도 가능하다.

    class Outer {
    
    	private String mString = "외부 인스턴스 멤버";
    
    	private void mMethod() {
    		System.out.println("외부 인스턴스 메서드");
    	}
    
    	class Inner {
    
    		String str = mString;
    
    		void method() {
    			mMethod();
    		}
    
    	}
    }

    • 메모리 누수

     

    https://d2.naver.com/helloworld/329631

     

    class Outer {
    
    	class Inner {
    		
    		public void printOuter() {
    			System.out.println(Outer.this);
    		}
    	}
    	
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    		Outer outer = new Outer();
    		System.out.println(outer.toString());
    
    		Outer.Inner inner = outer.new Inner();
    		outer = null; //외부 인스턴스 null
    		
    		inner.printOuter();
    		
    
    	}
    }

     

    non static 내부 클래스는 자기를 포함하는 인스턴스의 참조를 가지고 있다.

    outer = null; 로 초기화하여도 루트부터 inner -> Inner -> Outer가 참조가 가능하므로 가비지 컬렉션의 대상이 되지 않는다. 

    inner =null; 로 해주지 않으면 main함수의 종료까지 쓸데없이 메모리를 사용하게 된채로 어플리케이션이 종료될 때까지 지 메모리에 버티고 있는 것이다.


    • 사용가능한 변수, 메서드

     

    1. 인스턴스 멤버(변수,메서드)는 클래스 멤버,인스턴스 멤버 모두 사용가능

    2. 클래스 멤버는 클래스 멤버만 사용가능 (인스턴스 멤버 사용불가) . 인스턴스 멤버를 사용하려면 인스턴스를 생성한 뒤 사용해야함

     

    class Outer {
    
    	private static String sString = "클래스 멤버";
    	private String mString = "인스턴스 멤버";
    
    	private static String sMethod() {
    		return "클래스 메서드";
    	}
    
    	private String mMethod() {
    		return "인스턴스 메서드";
    	}
    
    	class Inner {
    		
    		//인스턴스 멤버는 외부의 모든 것 사용가능
    		private String str1 = sString;
    		private String str2 = sMethod();
    		private String str3 = mString;
    		private String str4 = mMethod();
    
    		//클래스 멤버는 외부의 클래스 멤버만 사용가능
    		private static String str5 = sString;
    		private static String str6 = sMethod();
    		private static String str7 = mString; // 에러
    		private static String str8 = mMethod(); // 에러
    
    		//인스턴스 멤버는 외부의 모든 것 사용가능
    		private void innerMethod() {
    			String str1 = sString;
    			String str2 = mString;
    			String str3 = sMethod();
    			String str4 = mMethod();
    
    		}
    
    		//클래스 멤버는 외부의 클래스 멤버만 사용가능
    		private static void innerStaticMethod() {
    			String str1 = sString;
    			String str2 = sMethod();
    			String str3 = mString; // 에러
    			String str4 = mMethod(); // 에러
    		}
    	}
    
    }

     

    • 외부 클래스와 내부 클래스의 메모리 로딩

     

    static{} 클래스 초기화 블럭:  클래스가 메모리에 처음 로딩될 때만 단 한번 호출된다.

     

    외부,내부 클래스 정의 상태

    class Outer {
    	
    	static String sOuterString;
    	
    	static {
    		System.out.println("외부 클래스 메모리 로딩");
    	}
    
    	class Inner {
    		
    		static String sInnerString;
    		
    		static {
    			System.out.println("내부 클래스 메모리 로딩");
    		}
    	}
    
    }

     

    main함수

     

    클래스를 메모리에 로딩시키기 위해 클래스 멤버(변수,메서드)를 호출한다.

    public class NestedClassTest {
    
    	public static void main(String[] args) {
    		
    		Outer.sOuterString="클래스 멤버에 값을 대입하여 클래스 메모리 로딩시킴";
    
    	}
    }

     

    public class NestedClassTest {
    
    	public static void main(String[] args) {
    
    		Outer.Inner.sInnerString = "클래스 멤버에 값을 대입하여 클래스 메모리 로딩시킴";
    
    	}
    }

     

    내부 클래스의 클래스 멤버가 호출될때 내부 클래스만 메모리에 로딩된다.

    외부 클래스가 같이 로딩되지 않았다.

    쉬운 이해를 위해 다음의 코드를 추가적으로 보자.

     

    class Outer {
    
    	static String sOuterString = "외부의 클래스 멤버";
    
    	static {
    		System.out.println("외부 클래스 메모리 로딩");
    	}
    
    	class Inner {
    
    		static String sInnerString;
    
    		static {
    			System.out.println("내부 클래스 메모리 로딩");
    			System.out.println("sInnerString: " + sInnerString);
    		}
    
    		static void sInnerMethod() {
    			System.out.println("내부의 클래스 메서드 호출");
    
    			sInnerString = sOuterString;
    			//main함수의 코드에 Inner부터 클래스 로딩시키므로
                		//Outer는 sOuterString을 사용되는 여기서 로딩됨
    
    			System.out.println("sInnerString: " + sInnerString);
    
    			System.out.println("내부의 클래스 메서드 종료");
    		}
    	}
    
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    
    		Outer.Inner.sInnerMethod();
    
    	}
    }

     

    main함수의 코드만 변경시킨 것 (외부 클래스를 먼저 로딩시킴)

    class Outer {
    
    	static String sOuterString;
    
    	static {
    		System.out.println("외부 클래스 메모리 로딩");
    	}
    
    	class Inner {
    
    		static String sInnerString;
    
    		static {
    			System.out.println("내부 클래스 메모리 로딩");
    			System.out.println("sInnerString: " + sInnerString);
    		}
    
    		static void sInnerMethod() {
    			System.out.println("내부의 클래스 메서드 호출");
    
    			sInnerString = sOuterString;
    
    			System.out.println("sInnerString: " + sInnerString);
    
    			System.out.println("내부의 클래스 메서드 종료");
    		}
    	}
    
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    
    		Outer.sOuterString = "외부의 클래스 멤버"; //외부 클래스 먼저 로딩
    		Outer.Inner.sInnerMethod();
    
    	}
    }

    이렇게 클래스 멤버의 동작을 알아봤다.

     

     

    그러나 내부 클래스는 외부 클래스의 도움 목적이므로, 외부 클래스의 클래스 멤버는 내부 클래스의 클래스 멤버를 참조할 수 없게 만들었다.


    static 내부 클래스

     

    • 인스턴스 생성법

     

    static 내부 클래스의 인스턴스는 외부 클래스의 인스턴스와 아무런 관계가 없다.

    즉 독자적으로 생성이 가능하다. 그러나 외부 클래스에 포함된 클래스이므로 new 외부클래스명.클래스();로 사용

    class Outer {
    	static class StaticInner {}
    }
    
    public class NestedClassTest {
    
    	public static void main(String[] args) {
    
    		Outer.StaticInner staticInner = new Outer.StaticInner();
    		System.out.println(staticInner);
    	}
    }


    • this 키워드

     

    외부 클래스의 인스턴스와 관계가 존재하지 않으므로 외부클래스.this같은 행위는 가능하지 않다.


    • 외부 클래스의 클래스 멤버만 사용가능하다.

     

    class Outer {
    	
    	static String sString = "외부의 클래스 멤버";
    
    	static void sMethod() {
    		System.out.println("외부의 클래스 메서드");
    	}
    
    	static class StaticInner {
    
    		static String innerStaticString= sString;
    		static void innerStaticMethod() {
    			sMethod();
    		}
    	}
    
    }

    • 클래스 메모리 로딩

     

    위에서 살펴본 non-static처럼 외부 내부는 독자적으로 클래스 로딩이 이루어진다.


    • 익명 클래스

    일회성으로 인스턴스를 전달하기 위해 사용된다.

     

    [Java/Class] - [Java] 익명 클래스

     

    [Java] 익명 클래스

    -익명 클래스란 class A 를 상속받아 어떠한 기능을 하는 class B를 만들어야 한다고 가정하자. class B extends A로 클래스 B를 선언한 뒤에 new B를 통해 객체를 생성한다. 만약 프로그램에서 클래스 B는

    hellose7.tistory.com

    익명 클래스 사용시 메모리 릭이 발생할 수 있는 상황이 존재한다.


    (내용 추가)

    kotlin object 선언식 공부중 막힌 자바 여러 중첩 레벨 클래스

     

    다음의 클래스 선언을 보자.

    Nested 클래스의 인스턴스를 생성할 때 Outer, Inner 인스턴스 모두 필요없다.

    (static클래스의 인스턴스는 모든 외부 클래스들의 인스턴스에 관계없이 독자적으로 생성될 수 있다)

    public class TwoLevelStaticClassTest {
    
    	public static void main(String[] args) {
    		
    		Outer.Inner.Nested nested= new Outer.Inner.Nested(); 
            	//모든 외부 클래스의 인스턴스 필요없다.
    		nested.method();
    	}
    }

     

    댓글

Designed by Tistory.