1. 소개
Java 인터페이스에 기본 메소드 가 도입된 후 인터페이스와 추상 클래스 사이에 더 이상 차이가 없는 것처럼 보였습니다. 그러나 그렇지 않습니다. 그들 사이에는 몇 가지 근본적인 차이점이 있습니다.
이 예제에서는 인터페이스와 추상 클래스가 어떻게 다른지 자세히 살펴보겠습니다.
2. 기본 방법을 사용하는 이유는 무엇입니까?
기본 방법 의 목적은 기존 구현을 중단하지 않고 외부 기능을 제공 하는 것입니다. 기본 방법을 도입한 원래 동기 는 새로운 람다 함수를 사용하여 Collection Framework에 이전 버전과의 호환성을 제공하는 것이었습니다.
3. 기본 메소드와 추상 클래스 가 있는 인터페이스
주요 근본적인 차이점을 살펴 보겠습니다.
3.1. 상태
추상 클래스 는 상태를 가질 수 있으며 해당 메서드는 구현의 상태에 액세스할 수 있습니다 . 인터페이스에서 기본 메서드가 허용 되지만 구현 상태에 액세스할 수는 없습니다.
기본 메소드에 작성하는 모든 로직 은 인터페이스의 다른 메소드와 관련되어야 합니다. 이러한 메소드는 객체의 상태와 무관합니다 .
CircleClass 객체 의 상태를 나타내기 위해 String , color 를 포함하는 CircleClass 추상 클래스를 생성했다고 가정해 보겠습니다 .
public abstract class CircleClass {
private String color;
private List<String> allowedColors = Arrays.asList("RED", "GREEN", "BLUE");
public boolean isValid() {
if (allowedColors.contains(getColor())) {
return true;
} else {
return false;
}
}
//standard getters and setters
}
위의 추상 클래스에는 상태에 따라 CircleClass 객체 의 유효성을 검사하는 isValid() 라는 비추상 메서드가 있습니다. isValid() 메서드는 CircleClass 객체의 상태에 액세스 하고 허용 된 색상을 기반으로 CircleClass 인스턴스의 유효성을 검사 할 수 있습니다. 이 동작으로 인해 객체의 상태를 기반으로 추상 클래스 메서드에 모든 논리를 작성할 수 있습니다 .
CircleClass 의 간단한 구현 클래스를 만들어 보겠습니다 .
public class ChildCircleClass extends CircleClass {
}
이제 인스턴스를 만들고 색상을 확인하겠습니다.
CircleClass redCircle = new ChildCircleClass();
redCircle.setColor("RED");
assertTrue(redCircle.isValid());
여기서 CircleClass 객체에 유효한 색상을 넣고 isValid() 메서드 를 호출하면 내부적으로 isValid() 메서드가 CircleClass 객체 의 상태에 액세스하여 인스턴스에 유효한 색상이 포함되어 있는지 확인할 수 있습니다. .
기본 메서드 가 있는 인터페이스를 사용하여 비슷한 작업을 시도해 보겠습니다 .
public interface CircleInterface {
List<String> allowedColors = Arrays.asList("RED", "GREEN", "BLUE");
String getColor();
public default boolean isValid() {
if (allowedColors.contains(getColor())) {
return true;
} else {
return false;
}
}
}
알다시피 인터페이스는 상태를 가질 수 없으므로 기본 메서드는 상태에 액세스할 수 없습니다.
여기에서는 상태 정보를 제공하기 위해 getColor() 메서드를 정의했습니다. 자식 클래스는 런타임에 인스턴스의 상태를 제공하기 위해 getColor() 메서드를 재정의합니다.
public class ChidlCircleInterfaceImpl implements CircleInterface {
private String color;
@Override
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
인스턴스를 만들고 색상을 확인하겠습니다.
ChidlCircleInterfaceImpl redCircleWithoutState = new ChidlCircleInterfaceImpl();
redCircleWithoutState.setColor("RED");
assertTrue(redCircleWithoutState.isValid());
여기에서 볼 수 있듯이 기본 메서드가 런타임에 상태를 확인 하도록 자식 클래스 의 getColor() 메서드를 재정의합니다.
3.2. 생성자
추상 클래스는 생성자를 가질 수 있으므로 생성 시 상태를 초기화할 수 있습니다 . 물론 인터페이스에는 생성자가 없습니다.
3.3. 구문상의 차이점
또한 구문과 관련하여 몇 가지 차이점이 있습니다. 추상 클래스는 Object 클래스 메서드를 재정의할 수 있지만 인터페이스 는 재정의할 수 없습니다.
추상 클래스 는 가능한 모든 액세스 한정자와 함께 인스턴스 변수를 선언할 수 있으며 자식 클래스에서 액세스할 수 있습니다. 인터페이스는 public, static 및 final 변수만 가질 수 있으며 인스턴스 변수는 가질 수 없습니다.
또한 추상 클래스는 인스턴스와 정적 블록을 선언할 수 있지만 인터페이스는 둘 중 하나를 가질 수 없습니다.
마지막으로 추상 클래스는 람다 식을 참조할 수 없지만 인터페이스는 람다 식을 참조할 수 있는 단일 추상 메서드를 가질 수 있습니다.
4. 결론
이 기사는 추상 클래스와 기본 메소드 가 있는 인터페이스의 차이점을 보여줍니다 . 또한 시나리오에 따라 가장 적합한 것이 무엇인지 확인했습니다.
가능하면 항상 기본 메서드가 있는 인터페이스를 선택해야 합니다. 클래스를 확장 하고 인터페이스도 구현할 수 있기 때문 입니다.
평소와 같이 이 문서에 표시된 모든 코드 샘플은 GitHub에서 사용할 수 있습니다 .