Java | 객체 지향 프로그래밍(2) - 다형성, final, 추상 클래스, 인터페이스

설탕·2023년 9월 22일
0

Java

목록 보기
4/4
post-thumbnail

🥊 이 글은 제대로 파는 자바 - Java 끝.장.내.기 (얄팍한 코딩사전) 강의 내용을 정리한 글입니다.

다형성 Polymorphism

  • 다형성: 특정 자료형의 자리에 여러 종류가 들어올 수 있는 것
    • 상속, 오버라이딩, 인터페이스 등을 통해 구현 가능
// 이전 글에 이어지는 예제 (Button)
public class Main {
	public static void main(String[] args) {
        // 가능 - 자식 클래스는 부모 클래스에 속함
        Button button1 = new Button("Enter");
        Button button2 = new ShutDownButton();
        Button button3 = new ToggleButton("CapsLock", true);

        // 불가 - 부모는 자식 클래스에 속하지 않음
        ShutDownButton button4 = new Button("Enter"); // error!
        // 불가 - 서로 다른 자식끼리는 포함 관계가 아님
        ToggleButton button5 = new ShutDownButton(); // error!
    }
}
// 편의: 모두 Button이란 범주로 묶어 배열 등에서 사용 가능
Button[] buttons = {
	new Button("Space"),
    new ToggleButton("NumLock", false),
    new ShutDownButton()
};

for (Button button : buttons) {
	bitton.onClick(); // 모든 버튼들은 onClick 메소드를 가짐
}
public class Main {
	public static void main(String[] args) {
    	YalcoChicken[] ycStores = {
        	new YalcoChicken(3, "판교"),
        	new YalcoChicken(17, "강남"),
        	new YalcoChickenDT(108, "철원"),
        };
        
        for (YalcoChicken store : ycStores) {
        	if (store instanceof YalcoChickenDT) {
            	// 자식 클래스의 기능을 사용하려면 명시적 타입 변환
            	((YalcoChickenDT) store).takeDTOrder();
            } else {
            	store.takeHallOrder();
            }
        }
    }
}

클래스의 final

final 필드

  • 값 변경 불가
  • 필드 선언 시 또는 생성자에서 초기화해야 함 (수정이 불가하므로...)

final 메소드

  • 자식 클래스에서 오버라이드 불가

final 인스턴스

  • 다른 값 재할당 불가
  • 인스턴스가 갖고 있는 필드는 변경 가능

final 클래스

  • 하위 확장 불가 (자식 클래스를 만들 수 없음)

추상 클래스

  • 스스로는 인스턴스를 만들 수 없음
    • 그냥 '포유류'라고 불리는 동물은 없는 것처럼...
  • 자식 클래스로 파생되기 위한 클래스
    • 개, 고양이, 말 등의 클래스로서 인스턴스 생성 (구상 클래스)
    • 관련된 여러 클래스들의 공통분모를 정의하기 위한 클래스

abstract 클래스

  • 그 자체로 인스턴스 생성 불가
    • YalcoGroup에서 매장을 낼 수는 없음
  • 부모 클래스로서는 일반 클래스와 같고, 다형성 구현됨
    • YalcoChickenYalcoCafe의 매장은 YalcoGroup 소속

abstract 메소드

  • 추상 클래스에서만 사용 가능
  • 스스로는 선언만 하고 구현하지 않음 - 자식 클래스에서 반드시 구현해야 함! (구현하지 않을 시 컴파일 에러)
  • 클래스 메소드(static)는 인스턴스를 생성해서 쓰는 것이 아니므로 추상 메소드로 작성할 수 없음
// YalcoGroup.java
public abstract class YalcoGroup {
	protected static final String CREED = "우리의 %s 얄팍하다";
    
    // 클래스 메소드는 abstract 불가
    abstract static String getCreed (); // error!
    
    protected final int no;
    protected final String name;
    
    public YalcoGroup(int no, String name){
    	this.no = no;
        this.name = name;
    }
    
    public String intro() {
    	return "%d호 %s점입니다.".formatted(no, name);
    }
    
    abstract void takeOrder();
    // public abstract void takeOrder(); // 접근제어자 의미 없음
}
// YalcoChicken.java
public class YalcoChicken extends YalcoGroup {
	public static String getCreed() {
    	return CREED.formatted("튀김옷은");
    }
    
    protected static int lastNo = 0;
    
    public YalcoChicken(String name) {
    	super(++lastNo, name);
    }
    
    // 추상 메소드는 반드시 구현해야 함!
    @Override
    public void takeOrder() {
    	System.out.printf("얄코치킨 %s 치킨을 주문해주세요.%n");
    }
}
// YalcoCafe.java
public class YalcoCafe extends YalcoGroup {
	public static String getCreed() {
    	return CREED.formatted("원두향은");
    }
    
    protected static int lastNo = 0;
    
    private boolean isTakeout;
    
    public YalcoCafe(String name, boolean isTakeout) {
    	super(++lastNo, name);
        this.isTakeout = isTakeout;
    }
    
    // 추상 메소드 반드시 구현
    @Override
    public void takeOrder() {
    	System.out.printf("얄코카페 %s 음료를 주문해주세요.%n", super.intro());
        if (!isTakeout) System.out.println("매장에서 드시겠어요?");
    }
}
// Main.java
public class Main {
	public static void main(String[] args) {
    	// 추상 클래스로 인스턴스 생성 불가
        YalcoGroup yalcoGroup = new YalcoGroup(1, "서울"); // error!
        
        YalcoChicken chickenStore1 = new YalcoChicken("판교");        
        YalcoChicken chickenStore2 = new YalcoChicken("강남");
        
        YalcoCafe cafeStore1 = new YalcoCafe("울릉", true);
        YalcoCafe cafeStore2 = new YalcoCafe("강릉", false);
        
        YalcoGroup[] ycStores = {
        	chickenStore1, chickenStore2,
            cafeStore1, cafeStore2
        };
        
        /*
        출력:
        얄코치킨 1호 판교점입니다. 치킨을 주문해주세요.
        얄코치킨 2호 강남점입니다. 치킨을 주문해주세요.
        얄코치킨 1호 울릉점입니다. 음료를 주문해주세요.
        얄코치킨 2호 강릉점입니다. 음료를 주문해주세요.
        매장에서 드시겠어요?
        */
        for (YalcoGroup ycStore : ycStores) {
        	ycStore.takeOrder();
        }
        
        System.out.println(YalcoChicken.getCreed()); // 출력: 우리의 튀김옷은 얄팍하다
        System.out.println(YalcoCafe.getCreed()); // 출력: 우리의 원두향은 얄팍하다
    }
}

인터페이스 Interface

추상 클래스 vs 인터페이스

추상 클래스인터페이스
extendsimplements
다중 적용 불가다중 적용 가능
상속관계에 의한 제한 있음상속관계에 의한 제한 없음
생성자 있음생성자 없음
구상 메소드, 추상 메소드 모두 가능추상 메소드(abstract 안 붙여도 됨), default 구상 메소드, 클래스 메소드
필드 모두 가능상수 필드만 가능 (final 명시 불필요)
  • 인터페이스는 다중 적용 가능
  • 다형성에 의해 자료형으로 작용 가능
  • 필드는 public static final (명시할 필요 X)
    • 생성자 없으므로 초기화 필수
  • 메소드는 public abstract (명시할 필요 X)
    • 메소드는 적용 클래스에서 구현 필수
  • Java8에서 추가된 기능들: 클래스 메소드, default 구상 메소드

default로 구상 메소드를 넣을 수 있도록 한 이유

  • 사용되던 인터페이스에 새로운 기능을 추가해야 한다면?
    • 새로운 자바 버전의 라이브러리 인터페이스에 새 기능이 추가되어야 한다면 그 인터페이스가 적용된 클래스들에 전부 다 구상 메소드를 새로 추가해줘야 할 것임...
  • 해당 인터페이스의 하위 클래스들을 일일이 수정하지 않아도 되도록, 즉 하위 호환성을 위해!
// FoodSafety.java
public interface FoodSafety {
	// 클래스 메소드
	static void announcement() {
    	System.out.println("식품안전 관련 공지");
    }
    
    // default 구상 메소드
    default void regularInspection() {
    	System.out.println("정기 체크");
    }
    
    // 추상 메소드 (abstract 명시 X)
    void cleanKitchen();
    
    void employeeEducation();
}
// YalcoChicken.java
public class YalcoChicken implements FoodSafety {
	// 인터페이스의 추상 메소드를 구현한 구상 메소드 필수!
	@Override
    public void cleanKitchen() {
    	System.out.println("매일 주방 청소");
    }
    
    @Override
    public void employeeEducation() {
    	System.out.println("직원 위생 교육");
    }
}
// Main.java
public class Main {
	public static void main(String[] args) {
    	FoodSafety.announcement(); // 식품안전 관련 공지
        
        YalcoChicken store = new YalcoChicken();
        
        store.regularInspection(); // 정기 체크
        store.cleanKitchen(); // 매일 주방 청소
        store.employeeEducation(); // 직원 위생 교육
    }
}
profile
공부 기록

0개의 댓글