본문 바로가기
BackEnd/Java

[Java] 내부 클래스 Inner Class

by summer_light 2021. 7. 22.

내부 클래스 Inner Class

class A{

	class B{

	}
}

위와 같이 클래스 내부에 또 다른 클래스가 존재할 수 있다.

BA의 내부 클래스이고, AB의 외부 클래스이다. 

 

내부 클래스 B는 외부 클래스인 A가 아닌 클래스에서 잘 사용되지 않아야 한다. 

외부 클래스가 아닌 다른 클래스에서 내부 클래스에 접근해야 한다면 내부 클래스로 선언해서는 안 되는 클래스를 내부 클래스로 선언했다는 의미이기 때문이다.

 

보통 AWT, Swing 등의 GUI 이벤트 처리 외에는 잘 사용되지 않는다.

 

 

 


내부 클래스의 장점

  1. 내부 클래스에서 외부 클래스의 멤버들에게 쉽게 접근이 가능하다.
  2. 코드의 복잡성을 줄여준다. (캡슐화)
    - 외부에는 불필요한 클래스를 감출 수 있기 때문이다.

 

내부 클래스의 종류와 특징 

class Outer{ //외부 클래스

	class InstanceInner{ } //인스턴스 클래스
    static class StaticInner{ } //스태틱 클래스

	void method(){
    	class LocalInner{ } //지역 클래스
    }

}
  1. 스태틱 클래스 : 외부 클래스의 멤버 변수 선언 위치에 선언
    • 외부 클래스의 static 멤버처럼 다뤄진다.
      내부 클래스에 static 변수를 선언해야 한다면 스태틱 클래스로 선언해야 한다.
      (단, staic final이 동시에 붙은 상수는 모든 내부 클래스에서 정의할 수 있다.)
    • 주로 외부 클래스의 static멤버, 특히 static메소드에서 사용될 목적으로 선언
    • 스태틱 클래스는 네스티드 클래스이지만, 내부 클래스(이너 클래스)로는 분류되지 않기도 한다. 
      (이 경우 멤버, 로컬, 익명 클래스만 네스티드 클래스이면서 이너 클래스)
  2. 멤버 클래스 :  외부 클래스의 멤버 변수 선언 위치에 선언
    • =인스턴스 클래스
    • 외부 클래스의 인스턴스 멤버처럼 사용
    • 주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에서 사용
  3. 지역 클래스 : 외부 클래스의 메소드나 초기화 블럭 안에서 선언.
    • 선언된 영역 내부에서만 사용
  4. 익명 클래스 : 클래스 선언과 객체의 생성을 동시에 하는 이름 없는 클래스(일회용)

 

package innerClass;
//멤버 클래스
/* 멤버 클래스와 static클래스는 외부 클래스의 멤버 변수와 같은
 * 위치에 선언됩니다. 또한 멤버 변수와 같은 성질을 가집니다.
 * 
 * 다른 책에서는 멤버 변수를 이렇게 말하고 있습니다. 
 * 정적 클래스 static이 아닌 경우 (static선언이 없으면)
 * 내부 클래스라고 부릅니다. 
 * 
 *  내부 클래스는 클래스 내에 선언되므로 인스턴스 속성 변수처럼
 *  활용됩니다. 
 *  즉 메소드 {} 안에서만 유효합니다.
 *  
 *  인스턴스 변수는 클래스 내에서 선언되지만 메소드 밖에서,
 *  생성자 밖에서, 다른 블록 밖에서 선언됩니다.
 *  (이경우 반드시 초기화가 필요합니다)
 *  
 *  내부 클래스는 외부 클래스의 멤버를 활용할 수 있지만
 *  외부 클래스는 내부 클래스의 멤버 변수를 활용할 수 없습니다.
 *  또한 static이 붙은 메소드 내에서는 내부 클래스의 객체 선언X
 *  
 */
public class MemberClass01 {
	private int outerDf = 10;
	private static int osi = 55;
	int number = 777;
	
	void outerMethod() {
		System.out.println(number);
		System.out.println(osi);
		System.out.println(this.osi);
	}
	
	static void outterSM() {
		System.out.println(osi);
		//System.out.println(number);//X
	}
	
	public class InnerClass{
		private int x = 100;
		int innerDf = 100;
		static final int ISI = 123;
		
		public void innerMethod() {
			int imnum = osi;//외부 클래스 private static int osi = 55;
			System.out.println(x);
			System.out.println(innerDf);
			System.out.println(ISI);
			System.out.println(number);
			System.out.println(outerDf);
		}
		
	}
	
	public static void main(String[] args) {
		MemberClass01 memberClass01 = new MemberClass01();
		
		//MemberClass01.InnerClass in = new MemberClass01.InnerClass();
		MemberClass01.InnerClass in = memberClass01.new InnerClass();
		in.innerMethod();
		//내부 클래스 -> 입출력 -> 쓰레드 -> 네트워킹 -> 그래픽

	}
	
	
	
	
	
	
	
}

 

package innerClass;
//static class
/* class앞에 static이 붙은 것이 차이점
 * static이 붙었기 때문에 객체 생성없이 사용가능합니다.
 * 클래스의 static 변수처럼 사용됩니다.
 * 외부 클래스와 내부 클래스는 다르게 동작합니다. 
 * 외부 클래스와 내부 클래스의 멤버가 private라도 상호 접근 가능
 * 경로만 지정된다면 단독으로 직접 사용할 수 있습니다.
 * 
 * 책 390
 */


public class StaticClass01 {
	private int num = 1;//객체 생성, 외부X
	int sc = num;//객체 생성. 외부O
	private static int outterSI = 0;//클래스명. 객체X, 외부X
	public static void outterMethod() {
		System.out.println(SInner.innerSM);
	}
	
	public static class SInner{
		private int innerMember = 200;
		private static int innerSM = 300;
		final int LV = 100;
		
		public static void innerMethod() {
			System.out.println("static 클래스 내부 static 메소드");
		}
		
		public void innerM() {
			System.out.println("static 클래스 내부 클래스");
			System.out.println("this.innerSM " + this.innerSM);
			//System.out.println("sc " + sc); 호출 불가
			System.out.println("outterSI" + outterSI);
		}
		
	}
	
	public static void main(String[] args) {
		StaticClass01 staticClass01 = new StaticClass01();
		StaticClass01.SInner si = new SInner();
		StaticClass01.SInner si2 = new StaticClass01.SInner();
		
		si.innerMethod();
		si.innerM();
		//si.innerMember;
		//si.LV;
		
		StaticClass01.SInner.innerMethod();
		//StaticClass01.SInner.innerM();객체 생성 후 호출
		
		
		//aaa객체 생성
		AAA aaa = new AAA();
		//System.out.println(aaa.BBB..);//불가 -> 얘가 안보이고
		//System.out.println(AAA.BBB.);//안보임 -> 얘가 오류뜨는데?

		AAA.BBB bbb = new AAA.BBB();
		System.out.println(bbb.number2);
		
		//bbb.number = 20;//The field AAA.BBB.number is not visible? 
		//BBB.number = 20;//BBB cannot be resolved to a variable?
		
	}
}

//private: 같은 클래스에서만 접근 가능
//내부 클래스 - 외부 클래스 서로 접근 가능 
class AAA{
	private static int innerNum = BBB.number;//내부 클래스의 pirvate 접근 가능
	private static int outternum = 100;
	
	static class BBB{
		private static int number = 10;
		int number2 = outternum;//외부 클래스의 private도 접근 가능
	}
}

 

 

package innerClass;
//지역클래스
/* Local Class
 * 메소드 안에 선언한 클래스
 * 선언한 메소드 내에서만 사용하기 위해서 내부에 선언합니다.
 *  메소드 안에서만 지역변수처럼 클래스를 활용하므로 
 *  메소드의 실행이 끝나면 지역 클래스는 제거됩니다.
 *  
 *  외부에서 인스턴스를 생성할 수 없습니다. 
 *  또한 static을 사용할 수 없습니다.
 *  instance변수 또는 메소드는 사용할 수 있습니다.
 *  
 *  final붙은 지역변수(상수처리)하거나 매개변수는
 *  지역 클래스의 메소드에서 접근 가능합니다.
 *  
 *  객체를 생성해서 활용해야 합니다. 
 *  컴파일 하면 외부 클래스$숫자+로컬 클래스명.class로 만들어집니다
 *  숫자는 서로 다른 메소드인 경우 같은 이름의 클래스가
 *  존재할 수 있어서 구분하기 위해서 붙입니다.
 *  
 * 
 */
public class LocalClass01 {
	private int a = 10;
	final int LV = 100;
	
	void method() {
		int in = 100;
		final int inD = 1000;
		
		class LocalClass{
			int no = 99;
			void msg() {
				no = no + 10;
				System.out.println("외부 a " + a);
				System.out.println(LocalClass01.this.a);
				System.out.println(in);
				System.out.println(inD);
			}
		}//LocalCalass 끝
		//지역 클래스가 선언된 메소드 안에서 객체를 만듭니다.
		LocalClass local = new LocalClass();
		local.msg();//객체 생성 후에 호출해서 사용합니다.
		
	}//메소드 끝
	
	
	public static void main(String[] args) {
		LocalClass01 localClass01 = new LocalClass01();
		localClass01.method();
	}


}

 

package innerClass;

import java.util.ArrayList;
import java.util.List;

//익명 클래스
/* Anonymous Class
 * 
 * 클래스 명 없는 클래스
 * 선언과 동시에 인스턴스 생성을 하나로 통합한 클래스
 * 클래스를 인수의 값으로 활용하는 클래스
 * 
 * 객체를 한번만 사용할 경우 사용합니다.
 * 클래스의 선언부가 없기 때문에 이름이 없으므로
 * 생성자를 가질 수 없습니다. 
 * 슈퍼 클래스의 이름이나 구현할 인터페이스를 구현하거나
 * 둘 이상의 인터페이스를 구현할 수 없습니다.
 * 오직 하나의 클래스를 상속받거나 하나의 인스턴스만 구현 가능합니다.
 * 
 * 코드 블럭에 클래스 선언을 하는 점만 빼고는
 * 생성자를 호출하는 것과동일합니다.
 * 
 * 객체를 구성하는 new문장 뒤에 클래스의 블럭{}을 첨부하여
 * 몸통을 닫는 형식으로 구성됩니다.
 * 
 * new 슈퍼 클래스 또는 인터페이스명(){};
 * 
 * 객체를 생성한 후에 {}; 즉 메소드를 구현한 블록이 있고
 * 블록 끝에는 세미콜론이 붙습니다.
 * 
 * 
 * new 뒤에 오는 생성자명이 기존 클래스명이면 익명클래스가
 * 자동으로 클래스의 하위 클래스가 됩니다.
 * 
 * 인터페이스인 경우에는 인터페이스를 상속하는 부모 클래스가
 * Object가 됩니다.
 * 
 * 
 */

interface Sound{	
	abstract void sound();//불완전 요소
}

abstract class Animal{
	String name;
	int age;
}

class Cat extends Animal implements Sound{

	@Override
	public void sound() {
		
	}

}

class Dog{
}
class Mouse{
}

class AMClass{
	public void method() {
		System.out.println("method");
	}
}


public class Anonymous {
	public static void main(String[] args) {
		//상속 -> 추상화 -> 인터페이스 -> 다형성
		//List<String> list = new List<String>();
		//이렇게 만들 수 없어요. = 미구현된 메소드 완벽하지 X
		//인터페이스는 상속받는 자식 클래스로 생성해요.
		AMClass amc = new AMClass() {
			@Override
			public void method() {
				System.out.println("오버라이드 했습니다.");
			}
		};
		
		amc.method();
		
	}
}

 

참고하면 좋은 글 

https://siyoon210.tistory.com/141

https://pridiot.tistory.com/52

 

'BackEnd > Java' 카테고리의 다른 글

[Java] 아파치 POI 설치 및 사용법  (0) 2021.07.26
[Java] IO Stream  (0) 2021.07.26
[Java] 예외 Exception  (0) 2021.07.19
[Java] 2진트리 Binary Tree  (0) 2021.07.19
[Java] 스택(Stack), 큐(Queue)  (0) 2021.07.19

댓글