abstract와 interface의 실제 활용

June Lee·2022년 10월 6일
0

Java

목록 보기
23/23

abstract

  • 상속에서 쓰임.

  • 추상 클래스가 설계도인 인터페이스를 구현(implements)하는 경우

public abstract class Car implements Transport {
	@Override
    public String ride(Object person) { return "default ride"; }
    
    @Override
    public Boolean drive() { return true; }
    
    @Override
    public <T> T getOff() { return null; }
    
    public <T> T openWindow() { return null; }
    
    public abstract String hookHorn();
}

-> 위 예시와 같이 Transport 인터페이스에 정의된 메서드들(반드시 모두 public abstract, 생략 가능)을 override하며 default가 되는 값을 반환해줄 수 있고, 정의되지 않은 추가 메서드들을 만들어줄 수도 있다(openWindow, hookHorn 같은..)

-> 이때 Transport 인터페이스에 정의된 모든 메서드들을 Car 추상 클래스에도 적어줘야하는건 아니다.


  • 추상 클래스가 추상 클래스를 확장(extends)하는 경우
public abstract class SportsCar extends Car {
	@Override
    public String ride(Object person) { return "default sports car ride" ; }
    public abstract String accelerate();
}

-> 오버라이딩을 통해 새로운 디폴트 값을 반환하고 싶거나, 새로운 abstract method(모델일 경우 필드)를 추가해주고 싶을 때

이때 주의할 점
추상 클래스를 상속 받은 클래스는 추상 클래스에 정의된 모든 추상 메서드를 오버라이딩을 통해 구현해주어야한다. 그렇지 않으면, 이 클래스 또한 추상 클래스가 되어야 한다.




interface

  • 설계도

  • 인터페이스가 인터페이스를 확장(extends)하는 경우

public interface BlockHoundIntegration extends Comparable<BlockHoundIntegration> {

    /**
     * Lets an integration apply the customizations (see {@link BlockHound.Builder})
     * before BlockHound is installed.
     *
     * @param builder an instance of {@link BlockHound.Builder} that is being installed
     */
    void applyTo(BlockHound.Builder builder);

    @Override
    default int compareTo(BlockHoundIntegration o) {
        return 0;
    }
}

-> 여기서는 BlockHoundIntegration 인터페이스가 Comparable 인터페이스를 확장하였다. 이때 이 인터페이스에서 compareTo를 오버라이딩하지 않았다면 BlockHoundIntegration을 이후에 구현(implements)할 클래스에서 해당 메서드를 구현해줘야한다.
하지만 이 경우에는 default 키워드를 사용하면서 compareTo를 오버라이딩하여 구현해주었다.

-> default 키워드는 인터페이스 내에서 (예외적으로) 일반 메서드 구현를 가능할 수 있게 만드는 키워드로, java 8부터 사용 가능하다.

-> 왜 하필 default 키워드가 붙냐면(디폴트 키워드는 원래 생략되는 애인데), 메서드에 아무 접근제어자가 붙지 않을 경우 interface에서는 public abstrac가 생략된 것으로 간주하기 때문이다.

인터페이스는 설계도를 만드는 작업인데, 이 설계도가 수정되지 않는게 가장 좋은 설계이겠지만,
어쩔 수 없이 수정해야할 경우 이를 implements한 모든 클래스를 수정하는 것을 막기 위해 인터페이스에서 default 키워드를 사용할 수 있도록 허락해주었다.
(즉 공통적으로 구현할거 같은 메서드를 상위 인터페이스에서 한번만 구현할 수 있도록..!!)


  • 인터페이스 내부에 inner class를 써주는 경우
public interface Transport {

    (public static final) class Car implements Transport {}

    @Getter
    @RequiredArgsConstructor
    class Taxi implements Transport {

        private final Driver driver;
    }
}

-> 인터페이스 내부의 이너 클래스(public static final이어야함)는 해당 interface를 구현해줘야한다. 이를 이용해서 Transport라는 공통 부모 타입을 갖는 Car, Taxi를 만들어주고 외부에서 이를 new Transport().Car()와 같은 식으로 인스턴스화해서 사용할 수 있다.

final이 붙은 class?
final이 class 앞에 붙으면 이 클래스는 부모 클래스가 되는 것이 불가능하다. 즉 상속이 불가능하다.
따라서 해당 클래스 내의 모든 메소드는 overrinding(재정의) 될 수 없다.

final이 붙은 method?
final이 붙은 메소드 또한 오버라이딩이 불가능하다.
이를 이용하면, 부모 클래스에서 정의한 메소드를 자식 클래스에서 재정의하지 않고 그대로 쓰도록 하는 것이 가능하다.

profile
📝 dev wiki

0개의 댓글