내부 클래스 (inner class) 란?
자바에서 내부 클래스 (inner class) 는 한 클래스 내부에 선언된 클래스를 말합니다. 내부 클래스를 선언하게 되면 내부 클래스와 외부 클래스라고 표현할 수 있다. 내부 클래스는 보통 외부 클래스와 연관이 있는 경우가 많고 다른 곳에서 거의 사용할 일이 없는 경우에 내부 클래스를 선언해서 활용을 한다.
class OuterClass {
private int num = 10;
class InnerClass {
public void display() {
System.out.println("num: " + num);
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.display(); // 출력: num: 10
}
}
내부 클래스의 종류
- 멤버 내부 클래스 (Member Inner Class) : 외부 클래스의 필드와 같은 위치에 선언되며, 외부 클래스의 인스턴스에 종속적입니다. 멤버 내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 있어야 생성할 수 있다.
- 정적 내부 클래스 (Static Inner Class) : 외부 클래스의 필드에 선언되지만, static 키워드를 사용하여 선언된다.정적 내부 클래스는 외부 클래스의 인스턴수와 독립적으로 존재할 수 있으며, 주로 관련있는 클래스들을 논리적으로 그룹화할 때 사용된다.
- 지역 내부 클래스 (Local Inner Class) : 메서드 내부에 선언되며, 선언된 메서드 내에서만 사용된다. 지역 내부 클래스는 해당 메서드의 지역 변수와 마찬가지로 스코프(블록의 유효범위)가 제한된다.
- 익명 내부 클래스 (Anonymous Inner Class) : 이름이 없는 내부 클래스로, 주로 인터페이스나 추상 클래스를 간편하게 구현할 때 사용된다. 익명 내부 클래스는 오직 하나의 인스턴스만 생성할 수 있으며, 주로 이벤트 처리나 콜백 구현에 사용된다.
멤버 내부 클래스 (Member Inner Class)
package useful.ch07;
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);
}
// 멤버 내부 클래스
class Author {
private String name;
private String email;
// 생성자에서 저자의 이름과 이메일을 초기화
public Author(String name, String email) {
this.name = name;
this.email = email;
}
}
}
package useful.ex06;
public class BookTest {
public static void main(String[] args) {
// 멤버 내부 클래스를 사용하는 설계 방식의 주요 이점
// 캡슐화를 강화
// - 내부적으로 어떤 기능이 있는지 숨길 수 있다
// 로직의 응집도 향상
// - 특정 기능이나 데이터를 사용하는 코드를 한 곳에 모으면,
// 코드의 응집도가 향상됩니다.
// 이는 코드를 이해하고 유지보수하기 쉽게 만들어 줍니다.
Book book = new Book("홍길동전", "허균", "허균@example.com");
book.printBookDetails();
// 외부에서 Book 안에 있는 내부클래스 Author에 쉽게 접근이 안됨
}
}
정적 내부 클래스 (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
// 우주선에 엔진 추가
// 생성자 의존 주입
// 메서드 의존 주입
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("달나라로 출발 합니다 슈웅~");
}
}
}// end of class
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();
// 사용하는 이유
// [논리적인 그룹화]
// 정적 내부 클래스는 외부 클래스와 논리적으로
// 관련 있는 클래스들을 그룹화 하는데 유용하다.
}// end of main
}// end of class
지역 내부 클래스 (Local Inner Class)
public class OuterClass {
// 외부 클래스의 메서드
public void display() {
// 지역 내부 클래스
class LocalInnerClass {
void printMessage() {
System.out.println("Hello from the Local Inner Class!");
}
}
// 지역 내부 클래스의 인스턴스 생성
LocalInnerClass inner = new LocalInnerClass();
// 메서드 호출
inner.printMessage();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
지역 내부 클래스는 특정 메서드 내에서만 정의되고 사용되는 클래스로, 메서드 실행 시에만 존재하고 메서드의 지역 변수처럼 동작한다. 이 클래스는 외부에서는 접근할 수 없으며, 주로 메서드 내에서 일회성 작업을 수행하는 객체를 생성할 때 유용하다.
익명 내부 클래스 (Anonymous Inner Class)
package useful.ch07;
/**
* 익명 내부클래스에 대해서 살펴 보자.
*/
public class Outter {
Runnable runable1; // 인터페이스 이다.
// 인터페이스는 기본적으로 객체를 만들 수 없다
// 하지면 익명 내부 클래스로 구현할 수 있다.
// 이런것들을 앞으로 우리는 구현 클래스라 부르자
public Outter() {
// Runnable 인터페이스를 구현 클래스로 만들었다.
// Outter 클래스 내부에 있고, 이녀석을 만들었지만
// 다른곳에서 부를 방법이 없다. 이름이 없음 - 익명
// 종합 하면 익명 내부 클래스 명칭 한다.
new Runnable() {
public void run() {
// ...
}
};
}
// 변수에 Runnable 구현 클래스 대입
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);
}
};
}
}
728x90