목적
인터페이스는 기본적으로 클래스가 구현해야 하는 행동의 규약을 정의. 다중 상속을 지언하며, 구현 클래스가 특정 동작을 반드시 구현하도록 강제
추상 클래스는 공통적인 속성과 동작을 정의하며 이를 상속받은 클래스에서 이를 구체화하거나 재사용하도록 합니다.
구현 여부
인터페이스는 모든 메서드가 기본적으로 추상 메서드로 default와 static 메서드가 추가되었지만 제한적이다.
추상 클래스는 추상 메서드와 일반 메서드를 모두 포함할 수 있습니다. 일반 필드와 상수를 모두 선언할 수 있음.
상속 및 구현
인터페이스는 다중 구현을 지원하며 한 클래스가 여러 인터페이스를 동시에 구현할 수 있다.
추상 클래스는 단일 상속만 가능하며 한 클래스가 여러 추상 클래스를 상속 받을 수 없음.
접근 제어자
인터페이스는 메서드는 항상 public abstract로 선언되며 생략해도 자동으로 적용. private 메서드를 포함할 수 있으나 인터페이스 내부의 코드 재사용을 위한 목적
추상 클래스는 접근 제어자의 제한이 없다.
사용 사례
인터페이스는 서로 연관 없는 클래스 간 공통 동작을 정의할 때 사용. ex) Comparable, Runnable 등
추상 클래스는 서로 밀접하게 연관된 클래스 간 공통적인 상태(필드)와 동작(메서드)를 정의할 때 사용.
ex) Animal 클래스에서 공통 필드(name)와 메서드(move()) 정의 후 이를 상속받은 Dog, Cat 등
public interface Animal {
void makeSound(); // 추상 메서드
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public abstract class Animal {
String name; // 일반 필드
public Animal(String name) {
this.name = name;
}
public abstract void makeSound(); // 추상 메서드
public void eat() { // 일반 메서드
System.out.println(name + " is eating.");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
Animal 인터페이스를 설계한 뒤, 개, 고양이, 새 등 다양한 구현체를 만들어 봅니다.Animal 인터페이스에 makeSound()와 move() 메서드 정의.List<Animal>에 여러 동물을 추가한 뒤, 루프를 돌면서 각 동물의 동작을 실행.public interface Animal {
void makeSound();
void move();
}
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
@Override
public void move() {
System.out.println("Dog runs.");
}
}
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
@Override
public void move() {
System.out.println("Cat jumps.");
}
}
public class AnimalTest {
public static void main(String[] args) {
List<Animal> animals = List.of(new Dog(), new Cat());
for (Animal animal : animals) {
animal.makeSound();
animal.move();
}
}
}
Shape를 만들어 공통적인 속성(예: 색상)과 동작(면적 계산)을 정의하고, 사각형, 원 등의 구체적인 도형 클래스를 구현.Shape에 색상 필드와 calculateArea() 추상 메서드 정의.public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
public abstract double calculateArea();
public void displayInfo() {
System.out.println("Color: " + color + ", Area: " + calculateArea());
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
public class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double calculateArea() {
return width * height;
}
}
public class ShapeTest {
public static void main(String[] args) {
List<Shape> shapes = List.of(
new Circle("Red", 5.0),
new Rectangle("Blue", 4.0, 6.0)
);
for (Shape shape : shapes) {
shape.displayInfo();
}
}
}
PaymentService 인터페이스를 정의하고, KakaoPay, NaverPay 등의 구현체를 작성.@Component와 @Autowired를 사용하여 구현체를 주입.@Primary, @Qualifier) 학습.public interface PaymentService {
void pay(int amount);
}
@Component
public class KakaoPayService implements PaymentService {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using KakaoPay.");
}
}
@Component
public class NaverPayService implements PaymentService {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using NaverPay.");
}
}
@RestController
public class PaymentController {
private final PaymentService paymentService;
@Autowired
public PaymentController(PaymentService paymentService) {
this.paymentService = paymentService;
}
@GetMapping("/pay")
public String pay(@RequestParam int amount) {
paymentService.pay(amount);
return "Payment completed.";
}
}
위 실습을 통해 인터페이스와 추상 클래스의 실제 활용 방법을 경험하고, 이를 백엔드 개발 과정에서 유연하게 적용하는 능력을 키울 수 있습니다.