- Java 세팅 및 실습은 Windows 환경에서 IntelliJ를 통해 진행되었습니다.
6. 다형성 - 추상클래스와 인터페이스
추상 클래스와 인터페이스는 Java에서 다형성을 구현하고, 코드의 구조를 설계할 때 중요한 역할을 합니다.
- 이 둘은 모두 객체 지향 프로그래밍에서 공통된 행동을 정의할 때 사용되지만, 그 용도와 특징이 다릅니다.
6-1. 추상 클래스 (Abstract Class)
- 추상 클래스는 클래스 자체로는 객체를 생성할 수 없고, 다른 클래스가 상속받아 구현을 완성해야 하는 클래스입니다.
- 추상 클래스는
완전한 메서드(구현이 있는 메서드)와 추상 메서드(구현이 없는 메서드)를 가질 수 있습니다.
- 추상 메서드는 해당 메서드를 상속받는 클래스에서 반드시 구현해야 합니다.
추상 클래스의 특징
- 부분적인 구현: 추상 클래스는 일부 메서드는 구현을 포함하고, 일부 메서드는 추상 메서드로 남겨둘 수 있습니다.
- 상속을 통한 확장: 추상 클래스는 상속을 통해 구체적인 클래스들이 공통된 행동을 공유하면서도, 구체적인 세부 사항을 각 클래스에 맞게 구현할 수 있도록 합니다.
- 멤버 변수와 메서드: 추상 클래스는 일반 클래스처럼 멤버 변수와 메서드를 가질 수 있습니다.
추상 클래스의 예시
abstract class Animal {
public void breathe() {
System.out.println("This animal is breathing.");
}
public abstract void sound();
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks.");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("Cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.breathe();
myDog.sound();
Animal myCat = new Cat();
myCat.breathe();
myCat.sound();
}
}
- 위 예시에서 Animal 클래스는 추상 클래스이며, sound() 메서드는 추상 메서드로 정의되어 있습니다. Dog와 Cat 클래스는 이 추상 메서드를 각각의 방식으로 구현합니다.
6-2. 순수 추상 메서드 (Pure Abstract Method)
- 순수 추상 메서드란, 메서드의 선언만 있고 아무런 구현이 없는 메서드를 말합니다.
- 이는 메서드의 동작을 전혀 정의하지 않고, 이를 상속받는 클래스가 반드시 구현하도록 강제합니다.
- 모든 메서드가 순수 추상 메서드로 이루어진 클래스를 인터페이스라고 합니다.
abstract class Shape {
public abstract void draw();
public abstract double calculateArea();
}
- 위 코드에서 draw()와 calculateArea()는 순수 추상 메서드로, 이 메서드를 가진 클래스를 상속받는 모든 클래스는 반드시 이 메서드들을 구현해야 합니다.
6-3. 인터페이스 (Interface)
인터페이스는 모든 메서드가 순수 추상 메서드로 이루어진 클래스와 유사한 구조를 가진 요소입니다.
- class 대신
interface라는 구문을 사용하여 정의하고, extends 대신 implements라는 구문을 사용하여 상속 및 구현을 합니다.
- 인터페이스는 클래스가 어떤 동작을 해야 하는지를 정의하며, 그 구현은 해당 인터페이스를 구현하는 클래스들이 담당합니다.
- 인터페이스는 다중 상속이 가능하므로, 한 클래스가 여러 인터페이스를 구현할 수 있습니다.
- 이는 다형성의 또 다른 형태로, 여러 기능을 한 클래스에 결합할 수 있게 합니다.
- 참고로 Java에서는 기본적으로 클래스의 다중 상속을 허용하지 않아서 하나의 클래스만을 extends 키워드로 상속 받을 수 있습니다.
- 또한
상속이라는 용어를 사용하는 클래스와 달리 인터페이스는 구현이라는 표현을 씁니다.
인터페이스의 특징
- 완전한 추상화: 인터페이스는 모든 메서드가 순수 추상 메서드로 되어 있어, 구현을 포함하지 않습니다.
- 이때 기본적으로
public abstract가 붙는데 이는 생략 가능하고, 생략이 권장됩니다.
- 다중 상속: 클래스와 달리 인터페이스는 여러 인터페이스를 동시에 구현할 수 있습니다.
- 상수: 인터페이스에서 정의된 변수는 기본적으로
public static final로 선언됩니다.
- 기본 메서드 (Java 8 이후): 인터페이스도 이제 기본 메서드(default method)를 가질 수 있으며, 이는 구현이 포함된 메서드입니다.
인터페이스의 예시
interface Drawable {
void draw();
}
interface Measurable {
double calculateArea();
}
class Circle implements Drawable, Measurable {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle.");
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
public class Main {
public static void main(String[] args) {
Circle circle = new Circle(5.0);
circle.draw();
System.out.println("Area: " + circle.calculateArea());
}
}
- 위 예시에서 Circle 클래스는 Drawable과 Measurable 인터페이스(interface)를 구현(implements)하고 있습니다.
- 각각의 인터페이스에 정의된 메서드를 Circle 클래스에서 구체적으로 구현해야 합니다.
6-4. 추상 클래스 vs 인터페이스
| 특징 | 추상 클래스 | 인터페이스 |
|---|
| 구현 여부 | 추상 클래스는 구현된 메서드와 추상 메서드를 모두 가질 수 있습니다. | 인터페이스는 모든 메서드가 기본적으로 순수 추상 메서드입니다. (단, Java 8 이후부터는 기본 메서드와 static 메서드를 가질 수 있음) |
| 상속/구현 | 한 클래스만 상속받을 수 있습니다. | 여러 인터페이스를 구현할 수 있습니다. |
| 멤버 변수 | 인스턴스 변수와 static 변수를 가질 수 있습니다. | 인터페이스에서 선언된 변수는 기본적으로 public static final로 간주되며, 상수를 정의할 수 있습니다. |
| 목적 | 클래스 간의 상속을 통해 기본적인 구현과 기능을 공유하도록 하는 데 사용됩니다. | 클래스가 특정 동작을 구현하도록 강제하는 데 사용됩니다. 예를 들어, 어떤 클래스가 "그릴 수 있다"거나 "측정할 수 있다"는 행동을 정의할 수 있습니다. |
| 용도 | 공통된 속성과 기능을 가진 클래스들을 그룹화할 때 사용됩니다. | 클래스가 어떤 기능을 반드시 구현하도록 강제할 때 사용됩니다. |
- 쉽게 말해서, 모든 메서드를 추상 메서드로 구현하는 경우엔 인터페이스를 쓰고 추가적으로 상속하려는 일반메서드가 있으면 추상 메서드를 사용하면 됩니다.
마무리
- 추상 클래스와 인터페이스는 Java에서 다형성을 지원하고, 코드의 구조를 체계적으로 설계하는 데 필수적인 요소입니다.
- 추상 클래스는 부분적으로 구현된 메서드를 포함하며, 공통적인 속성과 행동을 공유하는 클래스들을 묶는 데 사용됩니다.
- 인터페이스는 완전한 추상화를 제공하며, 구현해야 할 동작을 명시하는 데 사용됩니다. 인터페이스는 다중 상속을 지원하기 때문에, 클래스가 여러 동작을 구현할 수 있도록 합니다.
- 다음 포스팅에서는 초급 과정에서 다룬 내용들을 간략하게 정리해보고, 좋은 객체지향프로그래밍을 위해 필요한 원칙들을 다루어 마무리하도록 하겠습니다.