본문 바로가기

Java

Inner class ( 중첩 클래스 )

내부 클래스 (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
    }
}

 

내부 클래스의 종류

  1. 멤버 내부 클래스 (Member Inner Class) : 외부 클래스의 필드와 같은 위치에 선언되며, 외부 클래스의 인스턴스에 종속적입니다. 멤버 내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 있어야 생성할 수 있다.
  2. 정적 내부 클래스 (Static Inner Class) : 외부 클래스의 필드에 선언되지만, static 키워드를 사용하여 선언된다.정적 내부 클래스는 외부 클래스의 인스턴수와 독립적으로 존재할 수 있으며, 주로 관련있는 클래스들을 논리적으로 그룹화할 때 사용된다.
  3. 지역 내부 클래스 (Local Inner Class) : 메서드 내부에 선언되며, 선언된 메서드 내에서만 사용된다. 지역 내부 클래스는 해당 메서드의 지역 변수와 마찬가지로 스코프(블록의 유효범위)가 제한된다.
  4. 익명 내부 클래스 (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

'Java' 카테고리의 다른 글

표준 입출력  (0) 2024.05.14
자바 I/O 개론  (0) 2024.05.14
Thread에 wait와 notify ( 프로듀서 - 컨슈머패턴 )  (0) 2024.05.13
Map 인터페이스  (0) 2024.05.13
Set 인터페이스  (0) 2024.05.10