# 추상 클래스와 인터페이스
## 추상화 (abstract)
- 객체지향의 4대 특성 중 하나
- 정의
- 공통적인 특성을 추출하는 것
- 예시
- 아우디, 벤츠, BMW 클래스가 있다면, 자동차라는 추상 클래스를 만들고 공통적인 특성을 추출해서 자동차 클래스에 정의한다.
## 추상 클래스
- 추상 클래스는 인스턴스를 생성할 수 없음
- 일반적으로 하나 이상의 추상 메서드를 포함
- 공통된 로직은 추상 클래스에 작성하고, 각각의 구현 클래스에서 달라져야하는 부분만 추상 메서드를 오버라이딩해서 다르게 작성할 수 있다.
```java
public abstract class AbstractClass {
public void implementedMethod() {
System.out.println("AbstractClass implementedMethod");
this.abstractMethod();
}
abstract public void abstractMethod();
}
public class ExtendedClass extends AbstractClass {
@Override
public void abstractMethod() {
System.out.println("ExtendedClass abstractMethod");
}
}
```
### 추상 클래스는 인스턴스를 정말 생성할 수 없을까?
- 방법이 있긴 하다.
- new 키워드로 인스턴스 생성 -> 추상 메서드 구현
```java
public class AbstractClassExampleMain {
public static void main(String[] args) {
AbstractClass abstractClass = new AbstractClass() {
@Override
public void abstractMethod() {
// 이렇게 사용하려면 여기서 추상 메서드를 구현해야함
System.out.println("AbstractClass abstractMethod");
}
};
abstractClass.implementedMethod();
abstractClass.abstractMethod();
AbstractClass extendedClass = new ExtendedClass();
extendedClass.abstractMethod(); // Q. 바로 위에 있는 abstractClass 를 호출하는 걸까? 아니면 ExtendedClass 의 abstractMethod 를 호출하는 걸까? -> 실제 들어있는 인스턴스가 ExtendedClass 이기 때문에 ExtendedClass 클래스의 메서드를 호출한다.
}
}
```
- **Q. ExtendedClass의 인스턴스를 어떻게 AbstractClass의 참조형 타입(레퍼런스 타입)인 extendedClass에 넣을 수 있을까?**
- **Q. 클래스와 인터페이스의 차이점은?**
## 인터페이스
- 클래스는 하나만 상속받을 수 있지만 인터페이스는 여러 개 구현할 수 있음
- implements한 인터페이스를 반드시 구현해야 함
```java
public class ImplementsClass implements SomeInterface, AnotherInterface {
@Override
public void someMethod() {
System.out.println("ImplementsClass someMethod");
}
@Override
public void anotherMethod() {
System.out.println("ImplementsClass anotherMethod");
}
}
```
#### default 메서드?
- 인터페이스에 메서드 정의 기능
```java
public interface SomeInterface {
void someMethod(); // 추상 클래스에서 이미 정의된 추상 메서드를 호출하는 것과 동일하다.
default void defaultMethod() {
// 인터페이스에 메서드 정의 가능
this.someMethod(); // 정의되지 않은 메서드도 호출 가능
}
}
public class InterfaceExampleMain {
public static void main(String[] args) {
SomeInterface someInterface = new ImplementsClass();
someInterface.defaultMethod();
}
}
```
### 추상 클래스 vs 인터페이스 default 메서드
- 자바 8버전부터 인터페이스에도 default 메서드를 통해 메서드를 정의할 수 있는 기능이 추가됐다.
- 일반적으로 추상클래스를 사용해야만 하는 상황이 아니라면 인터페이스의 defualt 메서드를 사용하는 게 낫다. 왜냐하면 추상클래스보다 인터페이스가 더 추상적인 존재이기 때문
### Q. 추상 클래스를 사용해야만 하는 상황은?
- 인스턴스 변수(필드)가 필요한 경우
- 생성자가 필요한 경우
- Object 클래스의 메서드를 오버라이딩 하고 싶은 경우
## default 메서드
- **Q. 왜 등장했을까?**
- 만약 인터페이스에 새로운 메서드를 추가한 상황에서 그 인터페이스를 구현한 구현체가 100개라면? 100개의 구현체에 모두 새롭게 추가된 메서드를 구현해야한다.
- 기존의 구현을 고치지 않으면서 이미 공개된 인터페이스를 변경하기 위해 default 메서드가 등장했다.
### 동작원리
- 구현체가 로드될 때 인터페이스에 default 키워드가 붙어있는 메서드가 로드되면서 컴파일 시에도 아무 문제없이 실행이 가능하다. -> 기존의 코드를 최대한 수정하지 않으면서 설계된 인터페이스에 새로운 확장을 가능케 한다.
```java
public interface List<E> extends Collection<E> {
/// ....
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
```