미완성 설계도
틀(리턴값, 매개변수 등)만 잡아두고 상속받는 자손클래스가 오버라이딩 하는 것추상클래스는 미완성이기 때문에 인스턴스를 생성할 수 없으며, 자손 클래스에 의해 완성될 수 있다.
추상클래스 자체만으로는 클래스 역할을 다 하지는 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 조상클래스로서 중요한 역할을 한다.
abstract class 클래스 이름 {
// ...
}
추상클래스는 추상메서드를 포함하는 것을 제외하고는 일반 클래스와 다르지 않다. 생성자도 있고 멤버 변수도 가질 수 있다.
선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것
설계만 해놓고 실제 수행 내용은 작성하지 않은 메서드
abstract 리턴타입 메서드이름();
추상클래스로 부터 상속받는 자손클래스는 오버라이딩을 통해 조상인 추상클래스의 추상 메서드를 모두 구현해야한다.
만일 조상으로 부터 상속받은 추상메서드 중 하나라도 구현하지 않을 경우, 자손클래스 역시 추상클래스로 지정해야한다.
AudioPlayer 클래스는 조상의 추상메서드 모두를 오버라이딩 했지만
AbstractPlayer 클래스는 play 추상메서드만 오버라이딩 했기때문에 Abstract로 지정해야한다.
추상화: 클래스간의 공통점을 찾아내서 공통의 조상을 만드는 작업
구체화: 상속을 통해 클래스를 구현, 확장하는 작업
상속계층도를 따라 내려갈수록 클래스는 점점 기능이 추가되어 구체화의 정도가 심해지며, 번대로 올라갈수록 클래스는 추상화 정도가 심해진다. → 내려갈수록 "세분화", 올라갈수록 "공통요소"만 남는다.
인터페이스를 공부할 때는 추상클래스와 비교하면서 공부할 필요가 있다
인터페이스는 일종의 추상클래스 이다.
하지만 차이가 있다. 인터페이스는 추상클래스보다 추상화 정도가 강해서(진짜 완전 틀만 있다.) 몸통을 갖춘 일반 메서드 또는 멤버변수를 가질 수 없다. 오로지 추상메서드와 상수만을 가질 수 있다.
[추상클래스] : 미완성 설계도
[인터페이스] : 기본 설계도
→ 인터페이스도 미완성이기 때문에, 이를 사용해서 무엇을 한다기 보다는 다른 클래스를 작성하는데 필요한 요소이다.
: 클래스 작성법과 같으나, interface 키워드 사용
interface 인터페이스이름{
public static final 타입 상수이름 = 값;
public abstract 매서드이름(매게변수);
}
모든 멤버변수는 public static final, 모든 메서드는 public abstrat이다. (생략가능)
interface Movable{
void move (int x, int y); // public abstract 생략된 것
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable{ //다중 상속
}
다중상속의 단점으로 동일한 이름의 멤버변수 또는 메서드 선언부가 있을 경우 어떤 클래스의 것을 상속받을지 알 수가 없다. 그래서 자바는 다중상속을 허용하지 않지만 인터페이스는 가능하다. 그래서 사람들이 인터페이스로 다중상속을 할 수 있는 것을 알고 있지만, 인터페이스로 다중상속을 구현하지는 않는다.
만약 두 개의 클래스로부터 상속을 받아야 하는 상황이라면, 하나를 상속하고 나머지는 클래스 내부에 멤버로 포함시키는 방식으로 처리하거나 인터페이스로 만드는 방식을 사용한다.
→ 하나의 클래스를 상속받고 다른 클래스는 클래스 내부에 포함시켜 내부럭으로 인스턴 생성해서 사용한다.
리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한
클래스의 인스턴스를 반환하다느 것을 의미
개발시간을 단축시킬 수 있다.
: 인터페이스를 이용해 프로그램을 작성할 수 있고, 동시에 다른 한 쪽에서 인터페이스를 구현하는 클래스를 자겅하게 되면 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 동시에 개발이 가능
표준화가 가능하다.
: 일관되고 정형화된 프로그램 개발 가능 (같은 기본 틀을 사용하기 때문에)
서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
: 서로 상속 관계가 없는 클래스들 간에 하나의 인터페이스를 공통적으로 구현하도록 하여 관계를 형성할 수 있다.
독립적인 프로그래밍이 가능하다.
: 인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능하다. 직접적인 관계를 인터페이스를 이용하여 간접적인 관계로 변경하면, 하나의 클래스가 변경되더라도 다른 클래스에 영향을 미치지 않는 독립 프로그래밍이 가능하다.
[본질적인 이해]
클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.
메서드를 사용하는 쪽에서는 사용하려는 메서드의 선언부만 알면된다.
하지만 인터페이스를 사용하여 간접적인 관계를 바꿔주면서, 인터페이스를 매게체로 하여 서로 영향을 주지 않도록 분리할 수 있다.
클래스 A는 클래스 B,C의 메서드를 호출하지만, 인터페이스 I를 통한 간접적인 관계를 맺으므로써 서로에게 영향을 주지 않는다.
인스턴스를 직접 생성하지 않고, getInstance() 메서드를 통해 제공받는다. 이렇게 하면 다른 클래스의 인스턴스로 변경되어도 A 클래스를 변경할 필요가 없다.
JDK1.8부터는 추상메서드 이외에도 디폴트메서드와 static 메서드를 추가할 수 있다.
[디폴트메서드]
: 조상 클래스에 새로운 메서드를 추가하는 것을 별일이 아니다. 하지만 인터페이스에 새로운 추상메서드를 추가한다는 것은 이 인터페이스를 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야한다.
→ 이를 해결하기 위해 디폴트 메서드가 생겼다. 추상메서드가 아니기 때문에 새로 추가되어도 해당 인터페이스로 구현한 클래스를 수정할 필요가 없다.
- 여러 인터페이스의 디폴트 메서드 간의 충돌
: 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩 해야한다.- 디폴트 메서드와 조상클래스의 메서드 간의 충돌
: 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.