내부 클래스(중첩 클래스) & 익명 클래스
- 보통 인터페이스를 통해 추상 메서드를 만들고 클래스를 만들어 인터페이스를 구현해서 사용한다.
@FunctionalInterface
public interface Calculator {
int operate(int n1, int n2);
}
public class AddCalculator implements Calculator {
@Override
public int operate(int n1, int n2) {
return n1 + n2;
}
}
- 하지만 Main메서드에서만 필요하다거나 딱 한개의 메서드만 필요하다면 이렇게 불필요하게 클래스를 만들면 불편하지 않을까? 그래서 나온 개념이 내부 클래스와 익명 클래스이다.
내부 클래스
- 위 예시에 연장선으로 뺄셈 계산기를 만들려고하는데 실행할 때 Main 클래스 안에서만 사용하고 외부에서는 더이상 쓰지 않을 것 같을 때 내부 클래스를 사용한다.
- 위치는 Main 클래스와 Main 메서드 사이
- 자식 클래스를 생성할 때와 똑같이 인터페이스를 구현해서 오버라이딩해서 사용한다.
public class Main {
public static class SubCalculator implements Calculator {
@Override
public int operate(int n1, int n2) {
return n1 - n2;
}
}
public static void main(String[] args) {
Calculator cal;
cal = new AddCalculator();
int r1 = cal.operate(10, 20);
System.out.println("r1 = " + r1);
cal = new SubCalculator();
int r2 = cal.operate(50, 27);
System.out.println("r2 = " + r2);
익명 클래스
- 이름이 없는 클래스
- 클래스를 통해 객체 생성을 할 건데 일회용성으로 사용하는 클래스다. (재활용 X)
- main 메서드 안에서 생성해서 바로 일회용으로 사용한다.
- 위 예시에 이어서 곱셈을 익명 클래스로 만들어 보겠다.
cal = new Calculator() {
@Override
public int operate(int n1, int n2) {
return n1 * n2;
}
};
int r3 = cal.operate(10, 4);
System.out.println("r3 = " + r3);
- 위 코드처럼 똑같이 오버라이딩해서 사용하는 것을 볼 수 있다. 이렇게 사용하면 일회성으로 곱셈을 만들어 낼 수 있다.
익명 클래스 -> 람다 변환
- 익명 클래스는 람다식으로 변환이 가능하다.
- 단, 반드시 인터페이스 안의 추상메서드가 1개여야 람다로의 변환이 가능하다.
- 추상메서드가 1개인지 확인 가능하게 해주는 어노테이션이 있다.
@FunctionalInterface
이다. 인터페이스 위에 저 어노테이션을 써놓고 추상메서드가 1개가 넘어가게되면 빨갛게 에러가 뜨는 것을 볼 수 있다.
cal = (n1, n2) -> n1 * n2;
- 놀랍게도 위 곱셈식과 같은 식이다. Calculator가 operate 메서드를 가지고 있는 것을 알고 있고 {}와 return 생략이 가능한 점 등을 포함해서 저렇게 간단하게 나타낼 수 있다.
@FunctionalInterface
public interface Restaurant {
void cook();
}
public class FrenchRestaurant implements Restaurant {
@Override
public void cook() {
System.out.println("프랑스 요리를 합니다.");
}
}
Restaurant fr = new FrenchRestaurant();
Restaurant japaneseRestaurant = new Restaurant() {
@Override
public void cook() {
System.out.println("일식 요리를 합니다.");
}
};
Restaurant italian = () -> System.out.println("이탈리아 요리를 합니다.");
fr.cook();
japaneseRestaurant.cook();
italian.cook();
- 위 예시를 하나 더 보게되면
Restaurant 인터페이스를 FrenchRestaurant에서 구현하여 나타낼 수도 있고
익명 클래스를 활용하여 일회성있게 main 메서드에서 직접 구현할 수 있다. 또한 인터페이스에서 추상메서드가 1개 이기때문에 람다로의 변환해서 구현도 가능하다.