본문 바로가기
프로그래밍/JAVA

24 내부클래스와 익명클래스

by 윤지(●'◡'●) 2021. 4. 15.
반응형

 


내부클래스(inner class)

 

내부 클래스는 말 그대로, 클래스 내부에 선언된 클래스이다.

클래스 내부에 클래스를 선언하여 외부 클래스의 필드 접근에 용이하기 위한
내부 클래스의 필드를 사용하기 위해서는 외부 클래스에서 내부클래스를 객체화 해야한다.

 

[내부 클래스 객체화 문법]

외부클래스명 외부객체명 = new 외부클래스생성자();
외부클래스명.내부클래스명 내부객체명 = 외부객체명.new 내부클래스 생성자();

 

아래 예시를 보면, 내부클래스에서 외부클래스의 메소드, 변수에 접근이 용이한 것을 확인 할 수 있다.

package inner;

class Out {
	int outData;
	
	public Out() {
		System.out.println("외부 생성자 호출됨");
	}
	void printOut() {
		System.out.println("외부 클래스 메소드 호출됨");
	}
	
	class In{
		int inData;
		
		public In() {
			System.out.println("내부 생성자 호출");
		}
		
		void printIn() {
			printOut();	// 외부 클래스 메소드에 접근가능
			outData = 100; // 외부 클래스 변수에 접근가능
			System.out.println(outData);
		}
	}
}

public class InnerTest {
	public static void main(String[] args) {
		Out out = new Out();
		Out.In in = out.new In();	
		
	}
}

 

내부클래스를 사용하는 이유

 

- 캡슐화 ( 쉽게 말하면, 숨기기위해서 )

 

ex) 
A라는 클래스에서 a뿐만 아니라 b라는 작업도 자주 쓰이고, 이 작업은 B 클래스를 만들어야 쉽게 관리할 수 있다.

하지만 다른 클래스에서는 b작업이 쓰이지 않거나, B클래스를 외부에 노출 시키고 싶지 않을 때

내부 클래스로 선언한다.

 

 

 


익명 클래스(anonymous inner class)

 

이름이 없는 클래스(일회성으로 사용되기 위함)로 정의와 생성을 동시에 한다.

따라서 생성자를 선언할 수도 없으며, 오로지 단 하나의 클래스나 단 하나의 인터페이스를 상속받거나 구현할 수 있다.

이러한 익명 클래스는 매우 제한적인 용도에 사용되며, 구현해야 하는 메소드가 매우 적은 클래스를 구현할 때 사용된다.

 

new 조상클래스이름(){
	// 멤버선언
}

	//or

new 구현인터페이스이름(){
	// 멤버선언
} 

 

바로 예시로 살펴보자 : )

 

[문제]

스타벅스 체인점을 여러개 오픈한다.
스타벅스 본사에서는 새롭게 오픈한 매장의 메뉴와 판매방식이 필요하다.
체인점 오픈 시 반드시 스타벅스 본사에 등록해야한다.

 

1. Cafe interface 

// 객체들이 반드시 구현해야할 틀 제공
public interface Cafe {
	String [] getMenu();
	void sell(String choice);
}

 2. CafeAdapter class

// 인터페이스의 추상메소드 중, 강제성을 없애고 싶은 메소드 구현
public abstract class CafeAdapter implements Cafe{
	@Override
	public void sell(String choice) {;}
}

3. Starbucks class

public class Starbucks {
	//객체별 본사에 등록하는 메소드(객체별로 단 한번만 사용)
	void register(Cafe c) { // 외부에서 Cafe 타입을 전달 받음, 구현되지 않은 추상 메소드가 구현된 후 전달
		String [] menu = c.getMenu();
		for (int i = 0; i < menu.length; i++) {
			System.out.println(i + 1 + ". " + menu[i]);
		}
		// Adapter 사용 시 sell()을 구현하지 않기때문에
		if(!(c instanceof CafeAdapter)) {
			// sell()을 구현한 Cafe 타입만 들어옴
			c.sell("아메리카노");
		}
	}
}

4. Road main class

public class Road {

	public static void main(String[] args) {
		Starbucks gangnam = new Starbucks();
		// Cafe가 인터페이스이기 때문에 강제성이 있는 추상 메소드를 반드시 구현해야 한다.
		// 메소드를 선언하기 위해서는 반드시 클래스 안에서 선언해야 하고,
		// 열린 클래스 중괄호에는 이름이 없으며, 메소드 안에 선언된 내부 클래스 이다.
		// 이를 anonymouse inner class 라고 한다.
		// 소괄호 내 중괄호 형태
//		gangnam.register(new Cafe() {  <---- 바로 이 중괄호가 익명 클래스 중괄호
		gangnam.register(new Cafe() {
			
			@Override
			public void sell(String choice) {
				// 제작된 메뉴(getMenu()) 중 고객이 주문한 메뉴(choice)를 비교 후 일치하면 판매완료
				for (int i = 0; i < getMenu().length; i++) {
					if(getMenu()[i].equals(choice)) {
						System.out.println(choice + " 판매 완료");
					}
				}
				
			}
			
			@Override
			public String[] getMenu() {
				String [] menu = {"아메리카노","카페라떼","빵","홍차라떼"};
				//제작된 메뉴판 리턴
				return menu;
			}
		});
		
		// 무료나눔
		Starbucks jamsil = new Starbucks();
		
		jamsil.register(new CafeAdapter() {
			
			@Override
			public String[] getMenu() {
				String [] menu = {"아메리카노","카페라떼","빵","홍차라떼"};
				return menu;
			}
		});
	}
}

실행결과

1. 아메리카노
2. 카페라떼
3. 빵
4. 홍차라떼
아메리카노 판매 완료
1. 아메리카노
2. 카페라떼
3. 빵
4. 홍차라떼

 

반응형

댓글