개념적으로나 사용하는 목적에 있어서나 추상 클래스와 인터페이스는 비슷한 부분이 많다. 그러나 분명 차이점도 존재한다. 어떤 상황에 사용해야 적절한지 정확히 정리하고자 한다.
추상 메서드를 선언해 놓고, 상속을 통해서 자식 클래스에서 메서드를 완성하도록 유도하는 클래스이다. 하나 이상의 추상 메서드를 가지며, 추상 메서드를 선언했다면 자식 클래스는 해당 메서드를 반드시 재정의해서 구현하도록 강제된다.
abstract
키워드를 붙여 해당 클래스와 메서드가 추상 클래스, 메서드임을 나타낸다.extends
키워드를 사용하여 상속받게 된다. 자신의 기능들을 하위 클래스로 확장시키는 것과 비슷하다. -> 부모 클래스가 가진 기능들을 구현해야 할 경우 사용한다. (클래스끼리의 명확한 계층구조가 있다.)abstract class Animal {
abstract void cry();
}
Animal 추상 클래스를 선언했다. Animal 클래스는 cry() 추상 메서드를 가진다.
class Dog extends Animal {
void cry() {
System.out.println("멍멍!");
}
}
Animal 추상 클래스를 상속받은 Dog 클래스에서 cry() 메서드를 재정의한다.
class Cat extends Animal {
void cry() {
System.out.println("야옹~~");
}
}
Animal 추상 클래스를 상속받은 Cat 클래스에서 cry() 메서드를 재정의한다.
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.cry(); // 멍멍!
cat.cry(); // 야옹~~
}
}
오직 추상 메서드와 상수(static final)만을 가지고 있는 것을 인터페이스라고 한다. 추상 클래스와 마찬가지로 인터페이스 또한 인터페이스에 선언되어있는 추상 메서드를 implements 하는 클래스에서 반드시 구현하도록 강제한다.
public static final
이어야 하며, 이를 생략할 수 있다.public abstract
이어야 하며, 이를 생략할 수 있다. (Java 8 부터는 static
, default
메서드를 사용할 수 있다.)interface
키워드를 사용하여 정의할 수 있다.implements
를 사용한다.public interface Animal {
public static final String name = "동물";
public abstract void move();
public abstract void eat();
public abstract void cry();
}
Animal 은 인터페이스므로 static final로 생성할 수 있는 상수와 abstract로 생성할 수 있는 추상 메서드만 가질 수 있다.
public class Dog implements Animal{
@Override
public void move() {
System.out.println("슥슥~~");
}
@Override
public void cry() {
System.out.println("멍멍!");
}
}
Animal 인터페이스를 implements 키워드로 구현한 Dog 클래스에서 인터페이스의 추상 메서드들을 모두 재정의한다.
public class Cat implements Animal{
@Override
public void move() {
System.out.println("사뿐사뿐~~");
}
@Override
public void cry() {
System.out.println("야옹~~");
}
}
Cat 클래스도 마찬가지로 인터페이스의 추상 메서드들을 모두 재정의한다.
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.move(); // 슥슥~~
dog.cry(); // 멍멍!
cat.move(); // 사뿐사뿐~~
cat.cry(); // 야옹~~
}
}
종합해보자면, 둘다 내용에 대한 구현이 없는 선언부만 가진 추상 메서드를 사용하며, 독립적으로 객체를 생성할 수 없다. 그리고, 상속(구현)하도록 강제하기 위한 기능을 한다는 점도 같다.
abstract class Animal {
// 숨쉬기(일반 메서드(선언부 + 구현부 존재)
void breath() {
System.out.println("숨쉬기");
}
// 울음소리(추상 메서드(선언부만 존재)
abstract void cry();
}
interface Flyable {
// 날기(추상 메서드(선언부만 존재)
void fly();
}
Animal animal = new Animal(); // ERROR, 'Animal' is abstract; cannot be instantiated
Flyable flyable = new Flyable(); // ERROR, 'Flyable' is abstract; cannot be instantiated
// 추상적이므로 인스턴스화 할 수 없다는 에러 발생
공통점
구분 | 추상 클래스와 인터페이스 |
객체 생성 | 객체를 생성(인스턴스화)할 수 없다. |
추상 메서드 | 추상 메서드를 포함한다. |
기능적 목적 | 상속받는 클래스에서는 추상 메서드를 반드시 재정의하여 구현해야 한다. |
추상 클래스는 extends, 인터페이스는 implements를 상속 키워드로 사용한다.
키워드의 뜻에서 볼 수 있는 차이점을 생각해보자면
추상 클래스는 자신의 기능들을 하위로 확장시키는 기능 확장 느낌에 가깝고,
인터페이스는 인터페이스에 정의된 메서드들을 각 클래스의 목적에 맞게 동일한 기능으로 구현, 즉 실행하는 기능 구현에 중점을 둔 느낌이다.
상속해준 부모클래스의 면에서 차이점을 생각해보자.
추상 클래스 : 자식 클래스 is kind of 부모 클래스
인터페이스 : 자식 클래스 is able to 부모 인터페이스
추상클래스는 상속할 객체들의 공통점을 찾아 추상화시켜놓은 것이기 때문에, 상속 관계를 타고 올라가면 같은 부모 클래스를 상속하게 된다. 즉, 부모 클래스가 가진 기능들을 구현해야 하는 경우에 사용한다.
반면 인터페이스는 상속 관계를 타고 올라갔을 때, 다른 부모 클래스를 상속하더라도 같은 기능이 필요한 경우에 사용된다.
차이점
구분 | 추상 클래스 | 인터페이스 |
개념적 목적 | 상속 받아서 기능을 확장시키는데 목적 | 구현 객체의 동일한 실행 기능을 보장하기 위한 목적 |
클래스 | 클래스다.(abstract class) | 클래스가 아니다.(interface) |
일반 메서드 | 일반 메서드 정의가 가능 | 일반 메서드 정의 불가능 (Java8 이후 static, default 메서드 정의 가능) |
멤버 변수 | 클래스와 동일하게 변수 선언 및 사용 가능 | 상수만 사용 가능 |
상속 키워드 | extends | implements |
다중 상속 | 불가능 | 가능 |
[JAVA] 자바 추상클래스란?
[JAVA] 추상클래스와 인터페이스의 차이
[간단정리] JAVA - 추상클래스, 인터페이스 특징 및 차이점 확실히 기억하기