중첩클래스

오늘·2021년 3월 17일
0

Java

목록 보기
20/42
post-custom-banner

중첩 클래스와 중첩 인터페이스란

-클래스가 여러 클래스와 관계를 맺는 경우 독립적으로 선언하는 것이 좋으나, 특정 클래스와 관계를 맺을 경우에는 관계클래스를 클래스 내부에 선언하는 것도 좋다.

중첩 클래스(Nested Class)

-클래스 내부에 선언한 클래스
-코드의 복잡성을 줄일 수 있음
-두 클래스의 멤버들을 서로 쉽게 접근할 수 있다는 장점
-외부에는 내부를 감춤으로써 정보은닉, 캡슐화, 암호화하여 사용할 수 있다.

class ClassName {
	// 클래스 안에 클래스
	class NestedClassName {
    }
}

인스턴스 멤버 클래스

-static키워드 없이 선언된 클래스를 뜻함
-인스턴스 필드와 메소드만 선언 가능하고, 정적 필드와 메소드는 선언할 수 없다

/* 인스턴스 멤버 클래스 */
// static 불가
class B {
	int field1;
	//static int field2;
	void method1() {	}
	// static void method2() {	}
	B() {
		System.out.println("B 객체가 생성됨");
	}
}

정적 멤버 클래스

-static 키워드로 선언된 클래스
-static 이라 모든 종류의 필드와 메소드 선언 가능하다

/* 정적 멤버 클래스 */
static class C {
	int field1;
	static int field2;
	void method1() {	}
	static void method2() {	}
	C() {
		System.out.println("C 객체가 생성됨");
	}
}

로컬 클래스

-중첩 클래스는 메소드 내에서도 선언 가능 = 로컬클래스
-접근제한자(public, private) 및 static을 붙일 수 없다
-메소드가 실행될 때 메소드 내에서 객체를 생성하고 사용해야한다.

void method() {
	/* 로컬 클래스
	 메소드가 끝나면 D클래스는 힙메모리에서 소멸된다
	 */
	class D {
		int field1;
		// static int field2;
		void method1() {
			System.out.println("이곳은 로컬 클래스의 메소드");
			System.out.println("field1 : " + field1);
		}
		// static void method2() {	}
		D() {
			System.out.println("D 객체가 생성됨");
		}
	}
	System.out.println("로컬클래스에서 넣은 구분자----------");
	D d = new D();
	d.field1 = 30;
	d.method1();
}

중첩 클래스 호출하기

중첩 클래스는 new로 직접적 객체 생성이 불가하고, 2단계로 진행된다.
1. 외부 클래스를 객체화한 후
2. 내부 클래스를 객체화한다

class Class {
	class Nested {
    }
}


public class AMain {
	public static void main(String[] args) {
    		// 1단계
    		Class cn = new Class();
    		// 2단계
    		Class.Nested nested = cn.new Nested();
    	}
}

연습01

  1. 중첩 클래스
class A1 {
	
	A1() {
		System.out.println("A 객체가 생성죔");
	}
	
	/* 인스턴스 멤버 클래스 */
	class B {
		int field1;
		//static int field2;
		void method1() {	}
		// static void method2() {	}
		B() {
			System.out.println("B 객체가 생성됨");
		}
	}
	
	/* 정적 멤버 클래스 */
	static class C {
		int field1;
		static int field2;
		void method1() {	}
		static void method2() {	}
		C() {
			System.out.println("C 객체가 생성됨");
		}
	}
	
	void method() {
		/* 로컬 클래스
		 메소드가 끝나면 D클래스는 힙메모리에서 소멸된다
		 */
		class D {
			int field1;
			// static int field2;
			void method1() {
				System.out.println("이곳은 로컬 클래스의 메소드");
				System.out.println("field1 : " + field1);
			}
			// static void method2() {	}
			D() {
				System.out.println("D 객체가 생성됨");
			}
		}
		System.out.println("로컬클래스에서 넣은 구분자----------");
		D d = new D();
		d.field1 = 30;
		d.method1();
	}
}
  1. 호출 및 출력
public class Book395 {
	public static void main(String[] args) {
		A1 a = new A1();
		
		// 인스턴스 멤버 클래스 객체 생성
		A1.B b = a.new B();
		b.field1 = 3;
		b.method1();
		
		// 정적 멤버 클래스 객체 생성
		// 외부 클래스가 객체화되지 않아도 객체화 가능
		// static이니까
		A1.C c = new A1.C();
		c.field1 = 3;
		c.method1();
		// static 형이기 때문에 표기가
		// 클래스명.변수(메소드)명
		// 메소드영역에 컴파일할때 할당됨
		A1.C.field2 = 3;
		A1.C.method2();
		
		System.out.println("-----------------------");
		// 로컬 클래스 객체 생성을 위한 메소드 호출
		a.method();
	}
}

실행화면


중첩 클래스의 접근 제한

내부 클래스는 외부 클래스의 모든 멤버를 사용 가능
단, 생성자는 사용 불가

외부 클래스는 내부 클래스의 멤버를 사용할 수 없다
단, statc 필드값은 사용 가능

  1. 클래스 접근 제한 보기
// 클래스 (외부 클래스)
class A{
	// 필드
	int a;
	static double b = 3.14;
	static final int c = 0;
	
	// 일반 메소드
	void aM() {	}
	
	// 일반 클래스에 추상 메소드 작성은 불가
	// abstract void aaM();
	
	// 정적메소드
	static void stM() {	}
	
	// 생성자
	A(){
		// 내부에 있는 생성자 호출 불가
		// AA();
		System.out.println("외부 클래스의 기본 생성자 부분");
	}
	// 일반 메소드 오버로딩하기
	void iM(int a) {
		// 내부 클래스에 있는 필드값은 외부에서 사용 불가
		// aa = 200;
		
		// 내부에 있는 정적필드값은 사용 가능
		int b = AA.SAA + a;
		System.out.println("b 값 : " + b);
		System.out.println(" 외부 클래스의 일반 메소드 부분");
		// 내부 클래스에 잇는 일반 메소드 호출 불가
		// aaM();
	}
	
	// 일반메소드 오버로딩하기
	void aM(int a) {	}
	void aM(int a, String b) {    }
	boolean aM(boolean c) {
		return false;
	}
	
	// 생성자 오버로딩
	A(int a) {	}
	A(double b) {	}
	A(String c) {	}
	
	// 중첩 클래스 (내부 클래스)
	class AA{
		int aa;
		static final int SAA = 100;
		void aaM1() {
			System.out.println("내부클래스의 일반 메소드 aaM1() 부분");
		}
		// 내부 클래스에서 static 메소드를 생성하니 에러남
//		static void aasM() {	}
		
		void aaM() {
			System.out.println("이곳은 내부 클래스의 aaM() 부분");
			// 외부 클래스의 인스턴스 호출 사용 가능
			a = 10;
			// 외부 클래스의 상수 호출 가능
			double pi = b;
			// 외부 클래스의 메소드 호출 가능
			aM();
			// 외부 클래스의 정적메소드 호출 가능
			// 정적메소드의 호출은
			// 클래스명.정적 메소드명
			A.stM();
			
		}
		// 외부 클래스의 생성자 호출
		// 생성자는 생성자에서 호출한다
		AA() {
			// 에러남
			// A();
			// this.A();
			
			// 슈퍼의 경우는 에러는 안나지만 외부 클래스의 기본생성자를 가리키는게 아니라
			// Object의 기본 생성자를 가리킴
			// super()
		}
	}
}
  1. 호출 및 실행보기
public class AMain {
	public static void main(String[] args) {
		// 객체화시켜서 실제로 사용하기
		// 외부 클래스 사용하기
		A a = new A();
		a.iM(100);
		// 내부 클래스의 메소드는 외부 클래스의 참조 변수로 호출불가
		// a.aaM();
		// a.aaM1();
		
		// 내부 클래스 객체 (new)로 생성 불가
		// 암호화, 정보 은닉을 하기 위해
		//AA aa = new AA();
		
		// 내부 클래스를 객체화 할 수 있는 방법
		// 1단계. 외부 클래스를 객체화한다
		A a1 = new A();
		// 2단계. 내부 클래스를 객체화한다
		// = A클래스의 내부에 있는 AA를 객체화하겠다
		A.AA aa1 = a1.new AA();
		
		aa1.aaM1();
		aa1.aaM();
	}
}

실행 모습


중첩 클래스에서 바깥 클래스 참조

바깥클래스.this.필드
바깥클래스.this.메소드();

클래스 내부에서 this는 객체 자신의 참조이다. 중첩 클래스 내부에서 바깥 클래스의 객체 참조를 얻으려면 바깥 클래스의 이름을 this 앞에 붙여주면 된다.

예제 1)

public class ClassMain {
	public static void main(String[] args) {
		// I 클래스 객체화하기
		// 1  외부 객체생성 -> 2. 내부 객체 생성
		O o = new O();
		O.I oi = o.new I();
		
		// static은 단계없이 그냥 해도 가능
		O.SI si = new O.SI();
		
		// 외부 메소드 안에 있는 클래스
		// =로컬 클래스의 객체생성은 메소드를 실행하면 객체 생성이 된다
		o.oM();
		
		
		oi.printA();
	}
}



class O{
	int a = 10;
	class I{
		int a = 20;
		void printA() {
			System.out.println("내부 클래스의 a 값 출력하기 : " + this.a);
			System.out.println("외부 클래스의 a 값 출력하기 : " + O.this.a);
		}
	}
	static class SI{	}
	void oM() {
		class D{	}
		
		D d = new D();
	}
}

실행 모습

예제 2)

(1)
class Outter {
	String field = "Outter-field";
	
	void method() {
		System.out.println("Outter-method");
	}
	class Nested {
		String field = "Nested-field";
		
		void method() {
			System.out.println("Nested-method");
		}
		void print() {
			// 중첩 객체 참조
			// 그니까 여기의 this는 Nested에 있는 값을 참조
			System.out.println(this.field);
			this.method();
			// 외부 클래스 참조
			// 외부의 Outter에 있는 값을 참조
			System.out.println(Outter.this.field);
			Outter.this.method();
		}
	}
}




(2)
public class OutterEx {
	public static void main(String[] args) {
		Outter outter = new Outter();
		Outter.Nested nested = outter.new Nested();
		
		nested.method();
		System.out.println("-----");
		nested.print();
	}
}

실행 모습


post-custom-banner

0개의 댓글