카테고리 없음

Inner class(중첩 클래스)

동윤123 2024. 5. 14. 11:36

1. 내부 클래스란? (inner class)

2. 내부 클래스의 종류

 

1. 내부 클래스란? (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
    }
}

 

2. 내부 클래스의 종류

  1. 멤버 내부 클래스(Member Inner Class): 외부 클래스의 필드와 같은 위치에 선언되며, 외부 클래스의 인스턴스에 종속적입니다. 멤버 내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 있어야 생성할 수 있습니다.
  2. 정적 내부 클래스(Static Inner Class): 외부 클래스의 필드에 선언되지만, static 키워드를 사용하여 선언됩니다. 정적 내부 클래스는 외부 클래스의 인스턴스와 독립적으로 존재할 수 있으며, 주로 관련 있는 클래스들을 논리적으로 그룹화할 때 사용됩니다.
  3. 지역 내부 클래스(Local Inner Class): 메서드 내부에 선언되며, 선언된 메서드 내에서만 사용됩니다. 지역 내부 클래스는 해당 메서드의 지역 변수와 마찬가지로 스코프가 제한됩니다.
  4. 익명 내부 클래스(Anonymous Inner Class): 이름이 없는 내부 클래스로, 주로 인터페이스나 추상 클래스를 간편하게 구현할 때 사용됩니다. 익명 내부 클래스는 오직 하나의 인스턴스만 생성할 수 있으며, 주로 이벤트 처리나 콜백 구현에 사용됩니다.

 

1. 멤버 내부 클래스

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에 쉽게 접근이 안됨 
	}
}

 

2. 정적 내부 클래스(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();
		
		// 사용하는 이유
		// [논리적인 그룹화] 
		// 정적 내부 클래스는 외부 클래스와 논리적으로 
		// 관련 있는 클래스들을 그룹화 하는데 유용하다. 
		
	}

}

3. 지역 내부 클래스(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();
    }
}

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

 

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

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);

			}
		};
	}
}