내부, 중첩 및 익명 클래스
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 49번째.
Java는 다른 클래스 내부에 클래스를 정의할 수 있게 해줍니다. 이러한 내부 클래스(inner classes)는 관련된 기능을 함께 그룹화하여 코드를 구성하는 데 도움을 주며, 외부 클래스의 멤버에 직접 접근할 수 있습니다.
중첩 내부 클래스는 다른 클래스의 멤버로 정의됩니다. 이는 private 필드와 메서드를 포함하여 외부 클래스의 모든 필드와 메서드에 접근할 수 있습니다:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // private 필드에 접근 가능
}
}
}
// 사용법
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // 출력: Hello로컬 내부 클래스(local inner class)는 메서드 내부에 정의됩니다. 해당 메서드 내에서만 사용할 수 있으며, 사실상 final인 로컬 변수에 접근할 수 있습니다:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}익명 내부 클래스(anonymous inner class)는 이름이 없는 클래스로, 하나의 표현식에서 생성되고 인스턴스화됩니다. 이는 주로 인터페이스를 구현하거나 클래스를 즉석에서 확장하는 데 사용됩니다:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};내부 클래스는 클래스가 오직 하나의 다른 클래스와만 관련이 있을 때 특히 유용하며, 코드를 체계적으로 유지하고 캡슐화하는 데 도움이 됩니다.
챌린지
쉬움세 가지 유형의 내부 클래스를 모두 보여주는 쇼핑카트 시스템을 구축해 보겠습니다. 중첩 내부 클래스(nested inner class)를 사용하여 항목을 표현하고, 지역 내부 클래스(local inner class)를 사용하여 할인을 계산하며, 익명 내부 클래스(anonymous inner class)를 사용하여 최종 영수증 형식을 지정하는 ShoppingCart를 만들 것입니다.
코드는 두 개의 파일로 구성됩니다:
ShoppingCart.java: 쇼핑 경험을 관리하는 외부 클래스를 생성합니다. ShoppingCart는 private 필드인customerName(String)을 가져야 합니다.ShoppingCart 내부에
name(String)과price(double)라는 두 개의 private 필드를 가진 중첩 내부 클래스Item을 정의하세요. Item에 두 필드를 초기화하는 생성자와[name]: $[price]를 반환하는getDetails()메서드를 만드세요.ShoppingCart에는 고객 이름을 받는 생성자와, Item 및 할인율(double)을 인자로 받는
checkout()메서드가 필요합니다.checkout()내부에서 다음을 수행하세요:- 할인율을 적용한 후의 가격을 반환하는
applyDiscount(double originalPrice)메서드를 가진 지역 내부 클래스DiscountCalculator를 생성합니다. - 지역 클래스를 사용하여 최종 가격을 계산합니다.
- 영수증 형식을 지정하기 위해
Formatter인터페이스(직접 정의해야 함)를 구현하는 익명 내부 클래스를 생성합니다. 익명 클래스는 여러 줄로 된 영수증 문자열을 반환하는format()메서드를 오버라이드해야 합니다.
checkout()메서드는 다음의 정확한 형식으로 포맷된 영수증 문자열을 반환해야 합니다:--- Receipt --- Customer: [customerName] Item: [item details from getDetails()] Discount: [discount]% Final Price: $[calculated price]- 할인율을 적용한 후의 가격을 반환하는
Formatter.java: 단일 메서드String format()을 가진 간단한 인터페이스를 정의합니다. 이 인터페이스는 checkout 메서드 내부의 익명 내부 클래스에 의해 구현됩니다.Main.java: 쇼핑카트를 실행해 보세요! 고객 이름(String), 항목 이름(String), 항목 가격(double)의 세 가지 입력을 받게 됩니다. 할인율은10.0으로 고정되어 있습니다.고객 이름으로 ShoppingCart를 생성합니다. 그런 다음 외부 클래스 참조 구문인
cart.new Item(name, price)를 사용하여 Item을 생성합니다. 항목과 할인율을 사용하여checkout()을 호출하고 반환된 영수증을 출력하세요.
고객 이름, 항목 이름, 항목 가격 순으로 세 가지 입력을 받게 됩니다.
예를 들어, 입력이 Alice, Laptop, 1000.0인 경우, 10% 할인 후 최종 가격은 900.0이 됩니다.
각 내부 클래스 유형이 어떻게 서로 다른 목적으로 사용되는지 확인해 보세요. 중첩 클래스는 외부 클래스와 관련된 데이터를 그룹화하고, 지역 클래스는 하나의 메서드 내에서만 필요한 로직을 캡슐화하며, 익명 클래스는 인터페이스의 일회성 구현을 신속하게 제공합니다!
치트 시트
Java는 클래스 내부에 다른 클래스를 정의할 수 있도록 허용합니다. 이러한 내부 클래스(inner classes)는 관련된 기능을 함께 그룹화하여 코드를 정리하는 데 도움이 되며, 외부 클래스의 멤버에 직접 접근할 수 있습니다.
중첩 내부 클래스(Nested Inner Class)
중첩 내부 클래스는 다른 클래스의 멤버로 정의됩니다. 이 클래스는 private 멤버를 포함하여 외부 클래스의 모든 필드와 메서드에 접근할 수 있습니다:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // private 필드에 접근 가능
}
}
}
// 사용법
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // 출력: Hello지역 내부 클래스(Local Inner Class)
지역 내부 클래스는 메서드 내부에 정의됩니다. 해당 메서드 내에서만 사용할 수 있으며, 사실상 final인 지역 변수에 접근할 수 있습니다:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}익명 내부 클래스(Anonymous Inner Class)
익명 내부 클래스는 이름이 없는 클래스로, 하나의 표현식에서 생성과 인스턴스화가 동시에 이루어집니다. 주로 인터페이스를 구현하거나 클래스를 즉석에서 확장할 때 사용됩니다:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};내부 클래스는 특정 클래스가 오직 다른 하나의 클래스와만 관련이 있을 때 특히 유용하며, 코드를 체계적으로 유지하고 캡슐화하는 데 도움이 됩니다.
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 입력 읽기
String customerName = scanner.nextLine();
String itemName = scanner.nextLine();
double itemPrice = scanner.nextDouble();
double discount = 10.0;
// TODO: customerName으로 ShoppingCart 생성
// TODO: cart.new Item(itemName, itemPrice)를 사용하여 Item 생성
// TODO: item과 discount를 사용하여 checkout()을 호출하고 결과 출력
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조