220618_인터넷 강의_중첩(내부) 클래스

창고·2022년 10월 20일
0

티스토리에 저장했던 글을 옮겼습니다.
https://mrcocoball.tistory.com/89

1. 중첩 (내부 클래스)

(1) 인스턴스 멤버 클래스 (인스턴스 내부 클래스)

  • 내부적으로 사용할 클래스를 선언, private로 선언하는 것을 권장
  • 외부 클래스가 생성된 후 생성됨
  • private이 아닐 경우 다른 외부 클래스에서 접근, 생성이 가능함
  • 인스턴스 필드, 메소드만 선언이 가능하며 정적 필드, 메소드는 선언 불가
  • 예시
class OutClass {

	// field

	private int num = 10;
	private static int sNum = 20;
	private InClass inClass; // 내부 클래스 선언

	// constructor

	public OutClass() {
		inClass = new InClass(); // 내부 클래스 생성
	}

	class InClass { // 내부 클래스 

		int inNum = 100;
		// static int sInNum = 200; // 에러 발생, 정적 변수 사용 불가

		void inTest() {
			System.out.println("OutClass num = " + num + "(외부 클래스의 인스턴스 변수)");
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 정적 변수)");			
			System.out.println("InClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수)");
		}

		// static void sTest() { } // 에러 발생, 정적 메소드 사용 불가

	}

	public void usingClass() {
		inClass.inTest(); // 내부 클래스 사용해서 메소드 호출
	}
}

public class InnerTest_Instance {

	public static void main(String[] args) {
		OutClass outClass = new OutClass();
		System.out.println("외부 클래스 이용하여 내부 클래스 기능 호출");
		outClass.usingClass(); // 내부 클래스 기능 호출
		System.out.println();

		OutClass.InClass inClass = outClass.new InClass(); // 외부 클래스 이용, 내부 클래스 생성
		System.out.println("외부 클래스 변수 이용, 내부 클래스 생성");
		inClass.inTest(); // 내부 클래스의 내부 인스턴스 메소드 사용

	}

}

(2) 정적 멤버 클래스 (정적 내부 클래스)

  • 외부 클래스 생성과 무관하게 사용 가능
  • 정적 변수, 정적 메소드 사용
  • 모든 종류의 필드, 메소드 선언 가능
  • 외부/다른 내부 클래스의 인스턴스 변수 사용 불가
  • 예시
	static class InStaticClass { // 정적 내부 클래스

		int inNum = 100;
		static int sInNum = 200;

		void inTest() { // 정적 클래스의 일반 메소드
			// num += 10; // 외부 클래스의 인스턴스 변수 사용 불가
			System.out.println("InStaticClass inNum = " + inNum + "(내부 클래스의 인스턴스 변수 사용)");
			System.out.println("InStaticClass sInNum = " + sInNum + "(내부 클래스의 정적 변수 사용)");			
			System.out.println("OutClass sNum = " + sNum + "(외부 클래스의 정적 변수 사용)");
		}

		static void sTest() { // 정적 클래스의 정적 메소드
			// num += 10; // 외부 클래스의 인스턴스 변수 사용 불가
			// inNum += 10; // 내부 클래스의 인스턴스 변수 사용 불가

			System.out.println("OutClass sNum = " + sInNum + "(외부 클래스의 정적 변수 사용)");			
			System.out.println("InStaticClass sInNum = " + sNum + "(내부 클래스의 정적 변수 사용)");
		}
		
	}
	
}

public class InnerTest_Static {

	public static void main(String[] args) {
		
		// 외부 클래스 미생성 후 바로 정적 내부 클래스 생성
		OutClass.InStaticClass sInClass = new OutClass.InStaticClass();
		System.out.println("정적 내부 클래스 일반 메소드 호출");
		sInClass.inTest();
		System.out.println();
		
		System.out.println("정적 내부 클래스의 정적 메소드 호출");
		OutClass.InStaticClass.sTest();
	
		OutClass outClass = new OutClass();
		System.out.println("외부 클래스 이용하여 내부 클래스 기능 호출");
		outClass.usingClass(); // 내부 클래스 기능 호출
		System.out.println();

		OutClass.InClass inClass = outClass.new InClass(); // 외부 클래스 이용, 내부 클래스 생성
		System.out.println("외부 클래스 변수 이용, 내부 클래스 생성");
		inClass.inTest(); // 내부 클래스의 내부 인스턴스 메소드 사용
	}
}

(3) 로컬 클래스

  • 로컬 변수와 같이 메소드 내부에서 정의하여 사용하는 클래스
  • 접근 제한자 및 static 붙일 수 없음
  • 메소드가 실행되어야 사용할 수 있음
  • 메소드의 호출이 끝나면 메소드에 사용된 로컬 변수의 유효성이 사라짐
  • 메소드 호출 이후에도 사용해야 하는 경우가 있을 수 있으므로
    로컬 클래스에서 사용하는 메소드의 로컬 변수나 매개 변수는 final로 선언됨
    -> 따라서 외부의 로컬 변수 / 매개 변수에 값을 대입할 수 없음
  • 인스턴스 필드, 메소드만 선언 가능 (정적 필드, 메소드 선언 불가)
  • 비동기 처리를 위해 스레드 객체 생성 시 사용
  • 예시
class Outter {

	// field

	int outNum = 100;
	static int sNum = 200;

	// method

	Runnable getRunnable(int i) { // Runnable 타입 return

		int num = 100;

		class MyRunnable implements Runnable { // Runnable을 구현

			int localNum = 10;

			@Override
			public void run() {
				// num = 200; // 에러 발생, 로컬 변수는 상수로 바뀜
				// i = 100; // 에러 발생, 매개변수 역시 로컬 변수처럼 상수로 바뀜
				System.out.println("i = " + i); // getRunnable 메소드의 매개변수 i를 받음
				System.out.println("num = " + num); // getRunnable 메소드 내부 로컬 변수 100
				System.out.println("localNum = " + localNum); // MyRunnable 클래스의 로컬 변수 10

				System.out.println("outNum = " + outNum + "(외부 클래스 인스턴스 변수 사용)");
				System.out.println("Outter.sNum = " + Outter.sNum + "(외부 클래스 정적 변수 사용)");
				}
			}
		return new MyRunnable(); // MyRunnable() 호출
	}
}

public class InnerTest_Local {

	public static void main(String[] args) {
		
		Outter out = new Outter(); // 외부 클래스 생성
		Runnable runner = out.getRunnable(10); // Runnable 타입 runner = getRunnable 통해서 생성
		runner.run(); // runner 통해서 run 호출

	}

}

(4) 익명 멤버 클래스

  • 이름이 없는 클래스 (위 로컬 내부 클래스의 MyRunnable 클래스 이름은 실제로 호출되는 경우가 없음)
  • 클래스의 이름을 생략, 주로 하나의 인터페이스나 하나의 추상 클래스를 구현하여 봔한
    • 인터페이스나 추상 클래스 자료형의 변수에 직접 대입하여 클래스를 생성하거나
    • 로컬 클래스의 메소드 내부에서 생성, 반환할 수 있음
  • 익명 자식 객체 : 자식 클래스가 재사용되지 않고 오로지 특정 위치에서 사용할 경우 사용
부모클래스 [필드 변수] = new 부모 클래스(매개값, ...) {
// 필드
// 메소드
};
  • 익명 구현 객체 : 구현 클래스가 재사용되지 않고 오로지 특정 위치에서 사용할 경우 사용
인터페이스 [필드 변수] = new 인터페이스() {
// 인터페이스에 선언된 추상 메소드의 실체 메소드 선언
// 필드
// 메소드
};
  • 예시
class Outter2 {

	// method

	Runnable getRunnable(int i) { // MyRunnable() 을 지우고 익명 내부 클래스화

		int num = 100;

		return new Runnable() { // 익명 자식 객체 생성

		@Override
		public void run() {
			// num = 200; // 에러 발생
			// i = 10; / 에러 발생
			System.out.println(i);
			System.out.println(num);
			}
		};

	}

	Runnable runner = new Runnable() { // 익명 자식 객체 생성

		@Override
		public void run() {
			System.out.println("Runnable 이 구현된 익명 클래스 변수");
		}
	};
}

public class AnonymousInnerTest {

	public static void main(String[] args) {
		Outter2 out = new Outter2();

		Runnable runnable = out.getRunnable(10);
		runnable.run();

		out.runner.run();

	}

}
profile
공부했던 내용들을 모아둔 창고입니다.

0개의 댓글