추상 클래스
미완성 설계도라고도 표현하는 추상 클래스는 일반 클래스와 다를 것이 없다. 그저 클래스 내에 추상 메소드가 하나 이상 포함되거나 클래스가 abstract로 정의되어 있는 경우를 말하게 된다.
그렇게 추상적으로 선언이 된 메소드를 자식 클래스에서 상속받아 완성하게 하는 목표를 가진 것이라고 할 수 있다.
하지만 상속을 위한 클래스이기 때문에 따로 객체를 생성할 수는 없다.
abstract class name {
...
public abstract void methodName();
}
이런 식으로 추상 클래스 안에 추상 메소드가 들어가있는 것이다. 물론 추상이기 때문에 메소드의 구현부는 작성하지 않는다.
추상 클래스의 규칙
- 추상 클래스는 abstract를 붙여서 표현해야한다
- 클래스를 abstract로 지정하면 new를 통해 객체를 생성 할 수 없다.
- 메소드에 abstract를 사용한다면 interface의 메소드와 같이 구현 부분은 작성할 필요 없다.
- abstract로 선언한 메소드를 자식 클래스에서 반드시 구현해야 한다. 이는 자식 클래스에서 추상 메소드를 반드시 구현하도록 강제한다.
인터페이스
인터페이스는 기본 설계도라고 불릴수 있다. 인터페이스 또한 추상 클래스처럼 다른 클래스를 작성하는데 도움을 주는 목적으로 작성하고 클래스와 다르게 다중상속이 가능하다
interface Name {
public static final 상수 = 1;
public abstract void methodName();
}
인터페이스는 추상 클래스와 달리 몸통을 갖춘 일반 메소드, 멤버 변수는 가질수 없다.
아무것도 가질 수 없다 그저 그림을 그릴때 선만 그어놓은 밑그림과 같은 상황인 것이다.
인터페이스의 규칙
- 추상 클래스 처럼 불완전한 것이지만 그 자체만으로 사용되기 보다 다른 클래스를 작성하는데 도움을 줄 목적으로 작성된다.
- 일반 메소드 또는 멤버 변수를 구성원으로 가질 수 없다.
- 모든 멤버 변수는 public static final 이어야 한다. 이는 생략이 가능하다
- 모든 메소드는 public abstract 이고 마찬가지로 생략이 가능하다.
- 자바 버전이 8로 올라가면서 static 메소드와 default 메소드는 사용할 수 있다.
public static final은 왜 있는 걸까?
인터페이스 변수는 아무 인스턴스도 존재하지 않는 시점이기에 스스로 초기화 할 권한이 없다. 그래서 public static final을 사용해서 구현 객체의 같은 상태를 보장하게 된다.
인터페이스의 다중 상속
앞서 인터페이스는 다중 상속이 가능하다고 말했다. 먼저 자바는 다중 상속이 불가능하다. 그래서 이를 해결하기 위해 인터페이스를 통해 다중 상속을 진행하게 되는데 코드로 설명을 해보자
class MyVehicle extends car, plane {
@Override
public void goTo() {
super.drive();
}
}
위의 코드는 클래스를 다중 상속한 모양이다. 만약 car와 plane에 모두 drive라는 메소드가 존재한다면 goTo가 실행해야 할 super.drive는 무엇일까? 매우 애매모호해진다. 이때 다중 상속의 모호성이 생기는 것이다. 그래서 자바는 다중 상속을 없애버렸다.
그렇다면 인터페이스는 어떨까?
class Car implements vehicle, engine {
@Override
public void drive() {
@doSomething
}
}
클래스와 마찬가지로 여러개를 상속받았지만 이런 식으로 자식 인터페이스는 부모 인터페이스에 정의된 멤버 모두 상속을 받는다. 때문에 추상 메소드와 굉장히 많이 헷갈리기도 한다.
인터페이스의 사용 의도
추상 클래스와 인터페이스는 뭐가 어찌됬건 둘다 가지고 있는 추상 메소드를 구현하도록 강제한다. 또 인스턴스롸가 불가능하다.
그럼 그냥 추상 클래스 안에 원하는 것만 추상 메소드로 여러개 두거나 전부 추상 메소드로 만들면 되는거 아닌가? 그럼 추상 메소드가 인터페이스의 역할을 대신 해주지 않을까?
위에서 다중 상속에 대해 많이 말하기도 했지만 관점은 그게 아니다.
추상 메소드와 인터페이스의 관점은 사용 목적이 다르다는 것이다.
- 추상 클래스 : 상속할 각 객체들의 공통점을 찾아 추상화 시켜 놓은 것이다. 상속 관계를 타고 올라갔을땐 같은 부모 클래스를 상속하며 부모 클래스가 가진 기능들을 구현해야할 경우에 사용한다
- 인터페이스 : 상속 관계를 타고 올라갔을땐 다른 조상 클래스를 상속하더라도 같은 기능이 필요할 경우 사용한다. 클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장하기 위해 사용한다.
예를 들어보자
제일 부모 클래스인 Creature는 생물에 대한 Abstract Class 이다. 각 생물은 구분에 따라 Animal 또는 Plant를 상속한다. 그리고 각각이 할 수 있는 추가적인 기능들을 인터페이스로 구현했다.
여기서 눈여겨 봐야할 것은 Eatable이다. Animal과 Plant의 상속관계인 모든 클래스들중 Rose를 빼고 모두 Eatable할 수 있다.
이때 eat이라는 메소드를 어느 추상 클래스에 집어 넣기에는 굉장히 애매하다. 반드시 구현을 해야하는데 Rose는 못 먹기때문이다. 그래서 인터페이스를 사용하는 것이다.
보이는것 처럼 interface로 eat을 만들어 eat이 필요한 클래스에 implements해주어 사용하면 되는 것이다..
이는 가독성이 올라가고 유지보수 또한 매우 쉬워지는 장점이 있다
각각의 적절한 사용 케이스 정리
추상 클래스
- 관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우
- 추상 클래스를 상속 받을 클래스들이 공통으로 가지는 메소드와 필드가 많거나 public 이외의 접근자 선언이 필요할 경우
- non-static, non-final 필드 선언이 필요한 경우
인터페이스
- 서로 관련성이 없는 클래스들이 인터페이스를 구현하게 되는 경우
- 특정 데이터 타입의 행동을 명시하고픈데 어디서 그 행동이 구현되는지 신경쓰지 않아도 되는 경우
- 다중 상속을 허용하고 싶은 경우
reference
'CS > 📝 언어' 카테고리의 다른 글
🖨 new String() 과 ""의 차이 (0) | 2024.06.04 |
---|---|
🖨 절차 지향과 객체 지향 프로그래밍의 차이 (0) | 2024.05.22 |
🖨 OOP란?? (0) | 2024.05.22 |
Java의 컴파일 과정 & JVM의 구조 (0) | 2023.10.18 |
JIT 컴파일러 와 인터프리터 (0) | 2023.10.18 |