Java

2024.05.14 Java 유용한 클래스 Inner class(중첩 클래스)

정훈5 2024. 5. 14. 09:05

내부 클래스란? (inner class)

자바에서 내부 클래스(Inner Class)한 클래스 내부선언된 클래스를 말합니다.

내부 클래스를 선언하게 되면 내부 클래스와 외부 클래스라고 표현할 수 있습니다.

내부 클래스는 보통 외부 클래스와 연관이 있는 경우가 많고 다른 곳에서 거의 사용할 일이 없는 경우에 내부 클래스를
선언해서 활용을 합니다.

 

package useful.ch07;

class OuterClass {
	private int num = 10;

	public class InnerClass {
		
		public void Display() {
			System.out.println("num : " + num);
		} // end of Display()
		
	} // end of InnerClass()
	
} // end of OuterClass()

public class Main {

	public static void main(String[] args) {

		OuterClass outer = new OuterClass();
		OuterClass.InnerClass inner = outer.new InnerClass();
		inner.Display();

	} // end of main
} // end of class

 

 

내부 클래스의 종류

멤버 내부 클래스(Member Inner Class)

외부 클래스의 필드와 같은 위치에 선언되며, 외부 클래스의 인스턴스에 종속적입니다.
멤버 내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 있어야 생성할 수 있습니다.

 

정적 내부 클래스(Static Inner Class)

외부 클래스의 필드에 선언되지만, static 키워드를 사용하여 선언됩니다.
정적 내부 클래스외부 클래스의 인스턴스와 독립적으로 존재할 수 있으며, 주로 관련 있는 클래스들을 논리적으로
그룹화할 때
사용됩니다.

 

지역 내부 클래스(Local Inner Class)

메서드 내부에 선언되며, 선언된 메서드 내에서만 사용됩니다.
지역 내부 클래스는 해당 메서드의 지역 변수와 마찬가지로 스코프가 제한됩니다.

 

익명 내부 클래스(Anonymous Inner Class)

이름이 없는 내부 클래스로, 주로 인터페이스추상 클래스간편하게 구현할 때 사용됩니다.
익명 내부 클래스는 오직 하나의 인스턴스만 생성할 수 있으며, 주로 이벤트 처리나 콜백 구현에 사용됩니다.

 

멤버 내부 클래스

더보기
package useful.ch07;

 public class Book {
	private String title;
	private Author author;
	
	// 생성자에서 책의 제목과 저자의 정보를 초기화
	public Book(String title, String authorName, String authorEmail) {
		this.title = title;
		this.author = new Author(authorName, authorEmail);
	} // 생성자
	
	public void printBookDetails() {
		System.out.println("Book Title : " +title);
		System.out.println("작가 이름 : " + author.name + ", 이메일 : " +author.email);
	}
	// 멤버 내부 클래스
	public class Author {
		private String name;
		private String email;
		
		// 생성자에서 저자의 이름과 이메일을 초기화
		public Author(String name, String eamil) {
			this.name = name;
			this.email = email;
		} // Author 생성자
	} // end of Author class

} // end of Book class
package useful.ch07;

public class BookTest {

	public static void main(String[] args) {
		// 멤버 내부 클래스를 사용하는 설계 방식의 주요 이점
		// 캡슐화를 강화
		// - 내부적으로 어떤 기능이 있는지 숨길 수 있다
		// 로직의 응집도 향상
		// - 특정 기능이나 데이터를 사용하는 코드를 한 곳에 모으면,
		// 코드의 응집도가 향상됩니다.
		// 이는 코드를 이해하고 유지보수하기 쉽게 만들어 줍니다.
		Book book = new Book("홍길동", "허균", "허균@example");
		book.printBookDetails();
		
		// 외부에서 Book 안에 있는 내부클래스 Author에 쉽게 접근이 안됨 

	} // end of main

} // end of class

 

정적 내부 클래스(Static Inner Class)

더보기
package useful.ch07;

public class Spaceship {

	// 배열 - 이 우주선 설계는 엔진을 최대 3개 까지
	// 장착할 수 있다.
	private Engine innerEngine;

	// 정적 내부 클래스 Engine
	public static class Engine {

		public static int engineCount = 0;
		private int serialNumber;

		public Engine() {
			this.serialNumber = ++engineCount;
		}

		public void start() {
			System.out.println("Engine " + serialNumber + " 동작 합니다. 부릉~~");
		}
	} // end of inner class

	// 우주선에 엔진 추가
	// 생성자 의존 주입 DI
	// 메서드 의존 주입 관계
	public void addEngine(Engine engine) {
		innerEngine = engine;
		System.out.println("엔진 : " + innerEngine.serialNumber + " 을 장착 합니다");
		Engine.engineCount++;
	}

	public void startSpaceShip() {
		if (innerEngine == null) {
			System.out.println("엔진을 먼저 장착해주세요");
		} else {
			System.out.println("달나라로 출발 합니다 슈웅~");
		}
	}

}

 

package useful.ch07;

import useful.ch07.Spaceship.Engine;

public class SpaceshipTest {

	public static void main(String[] args) {

		Spaceship spaceship = new Spaceship();
		spaceship.startSpaceShip();

		// 외부에서 엔진을 만들어서
		// spaceship 주입 시켜야 한다.

		Engine 누리호1번엔진 = new Engine();
		Engine 누리호2번엔진 = new Spaceship.Engine();
		Engine 누리호3번엔진 = new Spaceship.Engine();
		// 변수명은 한글로 작성하지 말자 !!

		System.out.println("----------");
		spaceship.addEngine(누리호3번엔진);
		spaceship.startSpaceShip();

		// 사용하는 이유
		// [논리적인 그룹화]
		// 정적 내부 클래스는 외부 클래스와 논리적으로
		// 관련 있는 클래스들을 그룹화 하는데 유용하다.

	}

}

 

 

지역 내부 클래스(Local Inner Class)

더보기
package useful.ch07;

public class OuterClass_1 {
	
	// 외부 클래스의 메서드
	public void display() {
		
		class LocalInnerClass {
			void printMessage() {
				System.out.println("Hello from the Local Inner Class !");
			} // end of printMessage()
		} // end of  LocalInnerClass
		
		// 지역 내부 클래스의 인스턴스 생성
		LocalInnerClass inner = new LocalInnerClass();
		// 메서드 호출
		inner.printMessage();
	} // end of display()
	
	public static void main(String[] args) {
		OuterClass_1 outer = new OuterClass_1();
		outer.display();
	} // end of main

} // end of class

지역 내부 클래스는 특정 메서드 내에서만 정의되고 사용되는 클래스로,
메서드 실행 시에만 존재하고 메서드의 지역 변수처럼 동작합니다.
이 클래스는 외부에서는 접근할 수 없으며, 주로 메서드 내에서 일회성 작업을 수행하는 객체를 생성할 때 유용 합니다.

 

익명 내부 클래스 (익명이란? 이름이 없다 라는 의미 입니다.)

더보기
package useful.ch07;

public class Outter {

	Runnable runnable1; // 인터페이스 이다.

	// 인터페이스는 기본적으로 객체를 만들 수 없다
	// 하지면 익명 내부 클래스로 구현할 수 있다.
	// 이런것들을 앞으로 우리는 구현 클래스라 부르자

	public Outter() {
		// Runnable 인터페이스를 구현 클래스로 만들었다.
		// Outter 클래스 내부에 있고, 이녀석을 만들었지만
		// 다른곳에서 부를 방법이 없다. 이름이 없음 - 익명
		// 종합 하면 익명 내부 클래스 명칭 한다.
		new Runnable() {
			public void run() {
				// . . .
			}
		}; // end of Runnable()
	} // end of Outter()

	Runnable runner = new Runnable() {

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

		}
	};

	// 리턴 타입으로 Runnable 구현 클래스 반환
	Runnable getRunnable(int i) {

		int num = 100;

		return new Runnable() {

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

			}
		};

	}

} // end of class