
1️⃣ 상속
✔️ 상속 키워드: extends
상속은 하나의 클래스가 다른 클래스의 속성과 메소드를 물려받아 사용하는 개념입니다.
2️⃣ 인터페이스
인터페이스는 클래스가 반드시 구현해야 하는 메서드의 목록을 정의하는 일종의 계약입니다.
⭐ 메서드의 시그니처만 정의하고, 메서드의 구현은 포함하지 않습니다.
인터페이스에서는 전부 추상이기 때문에 메소드를 생성할 때
⭐ abstract 키워드를 명시하지 않아도 기본적으로 추상 메소드로 처리됩니다.
✔️ 상속 키워드: impleaments
public interface Animal {
void sound(); // 추상 메소드 (기본적으로 추상적)
// abstract 키워드를 명시하지 않아도 추상 메소드로 처리됨
abstract void move();
}
3️⃣ 추상 클래스
⭐ 추상 메서드가 하나라도 있는 클래스는 무조건 추상 클래스로 선언해야 한다.(인터페이스 제외)
⭐ 상속을 목적으로 사용 되는 클래스
⭐ 추상 메서드는 상속 받는 자식 클래스가 반드시 오버라이딩해서 사용해야 한다.
✔️ 상속 키워드: extends
abstract class Animal { // 추상 클래스
public abstract void sound(); // 추상 메소드(abstract 키워드 생략 불가)
}
추상 클래스는 완전하게 구현되지 않은 메서드(추상 메서드)를 포함할 수 있는 클래스입니다.
즉, 다른 클래스가 상속받아 사용하도록 만들어집니다.
추상 클래스는 일반 메서드와 필드도 가질 수 있으며, 이들 메서드는 구현이 되어 있어도 됩니다.
💬 동물이라는 추상 클래스가 있을 때, 고양이와 강아지는 동물을 상속받아 구체적인 동작을 구현할 수 있습니다.
4️⃣ Is-a / Has-a / Can-do 관계란?
◾ Is-a 관계(추상 클래스, 일반 클래스 사용)
동물과 개, 사각형과 정사각형 -> 상속의 개념
◾ Has-a 관계(한 클래스가 다른 클래스의 인스턴스를 멤버 변수로 포함)
자동차와 엔진, 도서관과 책 -> 가지다의 개념
◾ Can-do 관계(인터페이스 사용)
동물과 소리내기 -> 특정 행동의 개념
💡 인터페이스는 일반적으로 can-do
관계를 표현하지만
정의한 추상 메소드를 구현하면 구현한 (특정) 기능을 갖고 있을 수 있기 때문에 has-a
관계도 될 수 있습니다.
아래 예제를 통해 조금 더 자세히 살펴보겠습니다.
📎 인터페이스 has-a 관계 예제
/* 인터페이스 정의 */
public interface Animal {
void sound();
}
/* 인터페이스를 구현하는 클래스 정의 */
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("멍멍");
}
}
public class Cat implements Animal {
@Override
public void sound() {
System.out.println("야옹");
}
}
/* 인터페이스를 멤버 변수로 포함하는 클래스 정의 */
public class Zoo {
private Animal animal; // Animal 타입의 멤버 변수를 사용하여 Zoo는 Animal을 포함하는 has-a 관계를 가집니다.
public Zoo(Animal animal) {
this.animal = animal; // 생성자에서 Animal 객체를 초기화합니다.
}
public void letAnimalMakeSound() {
animal.sound(); // Animal 객체의 sound 메소드를 호출하여 소리를 냅니다.
}
}
/* has-a 관계를 사용하는 클래스 정의 */
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
Zoo dogZoo = new Zoo(dog);
Zoo catZoo = new Zoo(cat);
dogZoo.makeAnimalSound();
catZoo.makeAnimalSound();
}
}
Animal 인터페이스를 직접 객체로 만들 수 없기 때문에,
Zoo 클래스를 사용하여 Animal 객체를 포함하는 구조를 만든 것입니다.
이 구조를 통해 Animal 객체를 사용하는 방식으로 소리를 출력할 수 있습니다.
4️⃣ 추상클래스 vs 인터페이스 비교
✅ 구현 방식
특징 | 추상 클래스 | 인터페이스 |
필드 | O (일반 필드 및 상수 필드 모두 가능) | X (상수만 정의 가능, 모든 필드는 자동으로 public static final) |
생성자 | O (생성자 정의 가능) | X (생성자 정의 불가) |
일반 메소드 | O (정상 메소드 정의 가능) | 일부 가능 (default 메소드, static 메소드, private 메소드) |
추상 메소드 | O (추상 메소드 정의 가능) | O (추상 메소드 정의 가능, 모든 메소드는 기본적으로 추상 메소드) |
다중 상속 | 불가능 | O (다중 구현/상속 가능) |
💬 인터페이스에서 디폴트 메소드를 사용하는 이유?
인터페이스에 새로운 메소드를 추가하면서 기존 구현체에 영향을 미치지 않기 위해서이다.
📎인터페이스 can-do 관계와 예제
동물과 소리내기는 Can-do 관계라고 볼 수 있는데요.
Can-do 관계는 객체가 특정 행동이나 기능을 수행할 수 있음을 나타냅니다.
이를 상속이나 인터페이스의 개념으로 표현할 수 있는데
개인적으로 인터페이스로 나타내는게 적합한 것 같다는 생각이 들었습니다.
public interface Animal {
void sound();
}
public class Cat implements Animal{
public void sound(){
System.out.println("야옹");
}
}
public class Caw implements Animal {
public void sound(){
System.out.println("음매");
}
}
public class Dog implements Animal {
public void sound(){
System.out.println("멍멍");
}
}
public class AnimalSoundMain {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
Animal caw = new Caw();
System.out.println("동물 소리 테스트 시작");
dog.sound();
cat.sound();
caw.sound();
System.out.println("동물 소리 테스트 종료");
}
}
위 예제를 살펴보면 인터페이스에 정의한 메소드들은 다른 클래스에 무조건적으로 그 메소드를 구현해야된다는 것을 볼 수 있는데요. 반면 추상클래스는 무조건적으로 작성하지 않아도 됩니다. 따라서 인터페이스가 조금 더 강한 느낌을 가지고 있습니다. 마치 계약과 같은 존재이죠.
'☕ JAVA' 카테고리의 다른 글
[📖JAVA] 자바 예외 처리 try-catch-finally 이해하기➰(throw throws) (0) | 2024.09.11 |
---|---|
[📖JAVA]자바 다형성① 다형적 참조➰(업캐스팅, 다운캐스팅) (0) | 2024.09.10 |
[📖JAVA]자바 추상 클래스와 추상 메소 오버라이딩➰(abstract, @Override) (0) | 2024.09.09 |
[📖JAVA]접근 제어자 종류와 비교➰(public protected default private) (0) | 2024.09.06 |
[📖JAVA] 클래스 구성 요소(필드 생성자 메소드)와 객체 비교 (0) | 2024.09.05 |