1. 추상 클래스 (Abstract Class)
정의
- 추상 메서드를 포함할 수 있는 클래스
- 추상 메서드는 구현이 없는 메서드로, 해당 클래스를 상속받는 자식 클래스에서 반드시 구현해야 한다.
- 추상 클래스는 그 외에도 일반 메서드를 포함할 수 있다.
사용 이유
- 공통된 속성과 기능을 가진 클래스들 사이에서 코드 재사용을 목적으로 사용된다.
- 기본적인 구현을 제공하면서, 일부 기능만 자식 클래스에서 다르게 구현할 수 있도록 한다.
특징
1. 추상 클래스는 일부 메서드를 구현할 수 있다.
2. 멤버 변수와 생성자를 가질 수 있다.
3. 단일 상속만 가능하다. 즉, 한 클래스는 하나의 추상 클래스만 상속할 수 있다.
4. `abstract` 키워드를 사용하여 선언되며, 하나 이상의 추상 메서드를 포함할 수 있지만, 모든 메서드가 추상일 필요는 없다.
abstract class Animal {
String name;
// 추상 메서드 (구현 필요)
abstract void sound();
// 일반 메서드 (구현 제공)
void eat() {
System.out.println("Eating...");
}
}
class Dog extends Animal {
// 추상 메서드 구현
@Override
void sound() {
System.out.println("Bark!");
}
}
2. 인터페이스 (Interface)
정의
- 인터페이스는 추상 메서드들의 모음
- 인터페이스에 정의된 모든 메서드는 기본적으로 구현이 없고, 이를 구현하는 클래스가 모두 구현해야 한다.
- 자바 8 이후로는 인터페이스에서도 디폴트 메서드(기본 구현을 가진 메서드)와 정적 메서드를 가질 수 있게 됨
사용 이유
- 여러 클래스에서 공통된 행동을 정의하거나, 특정 기능을 강제하는 용도로 사용됨
- 상속과 달리 다중 상속이 가능하므로 유연하게 사용할 수 있습니다.
특징
1. 다중 구현이 가능 한 클래스는 여러 인터페이스를 동시에 구현할 수 있다.
2. 인터페이스는 일반적으로 구현을 포함하지 않는 메서드를 정의(자바 8 이후로 디폴트 메서드 및 정적 메서드 사용 가능)
3. 멤버 변수를 가질 수 없음 모든 필드는 기본적으로 `public static final`로 정의된다.
4. 클래스와 달리 다중 상속이 가능하므로, 다양한 기능을 추가할 수 있다.
interface Animal {
// 추상 메서드
void sound();
// 자바 8 이후의 디폴트 메서드
default void eat() {
System.out.println("Eating...");
}
}
class Dog implements Animal {
// 인터페이스 메서드 구현
@Override
public void sound() {
System.out.println("Bark!");
}
}
| 구분 |
추상 클래스 |
인터페이스 |
| 상속 가능성 |
단일 상속만 가능 (한 클래스는 하나의 추상 클래스만 상속 가능) |
다중 구현 가능 (한 클래스가 여러 인터페이스를 구현할 수 있음) |
| 메서드 구현 여부 |
구현된 메서드와 추상 메서드를 모두 포함할 수 있음 |
자바 8 이전에는 모든 메서드가 추상 메서드, 자바 8 이후로 디폴트 메서드 가능 |
| 멤버 변수 |
멤버 변수 가질 수 있음 |
멤버 변수를 가질 수 없음 (필드는 `public static final`로 고정됨) |
| 생성자 |
생성자 가질 수 있음 |
생성자 가질 수 없음 |
| 사용 목적 |
상태(멤버 변수)와 메서드를 공유하는 클래스들의 기본 기능 제공 |
클래스가 구현해야 할 기능(행동)을 정의하여 강제함 |
4. 언제 무엇을 사용해야 할까?
추상 클래스를 사용해야 할 때
- 여러 클래스가 공통된 상태(필드)를 가져야 하며, 일부 메서드에 기본적인 구현이 필요할 때
- 클래스를 상속받으면서 상속받은 기본 기능을 재사용하고 싶을 때
인터페이스를 사용해야 할 때
- 여러 클래스에 특정 기능을 강제하고, 그 기능의 구현 방식은 각각 다를 때
- 다중 상속이 필요한 경우
- 상태가 필요 없고, 행동(메서드)만 정의할 때
Q&A
Q. 인터페이스의 메서드들은 반드시 상속받은 클래스에서 구현해야한다는거 맞지? 반면 추상 클래스를 상속받으면 추상클래스의 모든 추상메서드를 다 수현할 필요가 없고
A:
1. 인터페이스의 메서드 구현
- 반드시 상속받은 클래스에서 구현해야 함: 인터페이스에 선언된 메서드들은 기본적으로 구현이 없기 때문에, 인터페이스를 구현하는 클래스는 반드시 그 메서드들을 구현해야 한다. (단, 자바 8 이후에는 디폴트 메서드를 사용하여 인터페이스 내에서도 일부 메서드에 기본 구현을 제공할 수 있다.)
interface Animal {
void sound(); // 반드시 구현해야 하는 메서드
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark!");
}
}
2. 추상 클래스의 메서드 구현
- 모든 추상 메서드를 반드시 구현할 필요는 없음: 추상 클래스에는 추상 메서드뿐만 아니라 일반 메서드도 포함될 수 있다. 추상 메서드만 자식 클래스에서 반드시 구현해야 하며, 이미 구현된 일반 메서드는 자식 클래스에서 그대로 사용할 수 있다.
abstract class Animal {
abstract void sound(); // 자식 클래스에서 구현해야 함
void eat() {
System.out.println("Eating..."); // 이미 구현된 메서드
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Bark!");
}
// eat() 메서드는 그대로 사용할 수 있음
}
Q. 멤버 변수는 추상클래스만 가질 수 있고, 인터페이스는 상수만 가질 수 있고 맞아?
A:
- 추상 클래스는 멤버 변수를 가질 수 있다. 추상 클래스는 일반 클래스처럼 필드(멤버 변수)를 정의하고, 이를 자식 클래스에서 상속받아 사용할 수 있다.
- 인터페이스는 상수(public static final 필드)만 가질 수 있습니다. 즉, 인터페이스에 정의된 변수는 항상 상수로 취급되며, 그 값을 변경할 수 없다.
// 추상 클래스
abstract class Animal {
String name; // 멤버 변수 (필드)
abstract void sound();
}
// 인터페이스
interface AnimalInterface {
static final int MAX_AGE = 100; // 상수만 가질 수 있음
void sound();
}
Q. 추상클래스에서 생성자를 가져?
A: 추상 클래스도 생성자를 가질 수 있다.
추상 클래스는 완전히 구현되지 않은 클래스이지만, 상속을 통해 자식 클래스에서 사용될 때 필요한 초기화를 위해 생성자를 정의할 수 있다. 다만, 추상 클래스 자체는 객체를 생성할 수 없기 때문에, 직접적으로 추상 클래스의 생성자를 호출하여 인스턴스를 만들 수는 없다. 자식 클래스가 추상 클래스를 상속할 때 부모 클래스인 추상 클래스의 생성자를 호출하여 초기화가 이루어질 수 있다.
abstract class Animal {
String name;
// 추상 클래스에도 생성자를 정의할 수 있음
public Animal(String name) {
this.name = name;
System.out.println("Animal 생성자 호출됨");
}
// 추상 메서드
abstract void sound();
}
class Dog extends Animal {
// 자식 클래스에서 부모의 생성자를 호출
public Dog(String name) {
super(name); // 부모 클래스(추상 클래스)의 생성자 호출
}
@Override
void sound() {
System.out.println(name + " says: Bark!");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy"); // 자식 클래스의 객체 생성
dog.sound();
}
}