추상화는 객체 지향 프로그래밍의 중요한 개념 중 하나로, 불필요한 세부 사항을 숨기고 중요한 부분만을 표현하는 기법이다. java에서는 추상클래스(Abstract Class)와 인터페이스(Interface)를 사용하여 구현한다.
추상 클래스
- abstract 키워드를 사용하여 선언
- 하나 이상의 추상 메서드 포함
- 인스턴스 직접 생성 불가능 → 하위클래스가 상속받아 구현
abstract class Animal {
abstract void makeSound(); // 추상 메서드 (구현 없음)
void eat() { // 일반 메서드 (구현 있음)
System.out.println("This animal is eating.");
}
}
class Dog extends Animal {
@Override //하위 클래스에서 추상 메서드 구현
void makeSound() {
System.out.println("Bark! Bark!");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound(); // "Bark! Bark!"
myDog.eat(); // "This animal is eating."
}
}
- abstract 키워드가 포함된 클래스는 객체를 생성할 수 없다. (메서드 실행 불가)
- 추상 메서드는 반드시 하위 클래스에서 구현해야 한다.
- 일반 메서드 또한 상속 받은 하위 클래스의 인스턴스를 통해 실행해야 한다.
다만, 업캐스팅을 통해 참조 변수를 이용한다면 추상 클래스 객체를 사용할 수 있다.
Animal myAnimal = new Dog(); // 업캐스팅 (Animal 타입으로 참조)
myAnimal.eat(); // "This animal is eating."
myAnimal.makeSound(); // "Bark! Bark!"
static 변수와 메서드는 객체 생성이 필요없으므로 추상 클래스에서도 활용할 수 있다.
단, 추상 메서드 + static은 선언 불가
추상클래스에서도 일반 변수 사용이 가능하다.
abstract class Animal {
String name; // 인스턴스 변수
static int count = 0; // static 변수 (클래스 변수)
final String species; // final 변수 (한 번 설정 후 변경 불가)
// 생성자
Animal(String name, String species) {
this.name = name;
this.species = species;
count++; // 객체 생성될 때마다 증가
}
void showInfo() {
System.out.println("Name: " + name + ", Species: " + species);
}
abstract void makeSound();
}
// 하위 클래스에서 추상 메서드 구현
class Cat extends Animal {
Cat(String name) {
super(name, "Feline");
}
@Override
void makeSound() {
System.out.println("Meow! Meow!");
}
}
public class Main {
public static void main(String[] args) {
Cat cat1 = new Cat("Kitty");
Cat cat2 = new Cat("Tom");
cat1.showInfo(); // "Name: Kitty, Species: Feline"
cat2.showInfo(); // "Name: Tom, Species: Feline"
System.out.println("Total animals: " + Animal.count); // "Total animals: 2"
}
}
super() 를 통해 부모 클래스의 생성자를 호출하여 변수 초기화
부모 클래스의 생성자(매개변수가 있을 경우)는 반드시 하위 클래스에서 호출해야 한다. (super사용 해야함)
하지만, 부모클래스에서 생성자를 만들지 않거나 기본 생성자를 사용하면 호출할 필요가 없다.
인터페이스 (Interface)
- interface 키워드를 사용하여 선언
- 모든 메서드는 기본적으로 public abstract 이며 구현이 없다.
- implements를 사용해 다중 구현 가능
- 모든 필드는 기본적으로 public static final 상수
다중 구현 예시
interface Animal {
void makeSound(); // 추상 메서드 (abstract 생략됨)
}
interface Pet {
void play(); // 추상 메서드
}
class Dog implements Animal, Pet { // 여러 개의 인터페이스 구현 가능
@Override
public void makeSound() {
System.out.println("Bark! Bark!");
}
@Override
public void play() {
System.out.println("Playing fetch!");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound(); // "Bark! Bark!"
myDog.play(); // "Playing fetch!"
}
}
클래스도 여러개의 하위 클래스를 상속할 수 있는데 왜 단일 상속이라 하는걸까?
한 클래스가 여러 개의 부모 클래스를 상속받을 수 없다는 의미에서 단일 상속을 의미한다.
상수 예시
interface Animal {
int LEGS = 4; // 자동으로 public static final
}
public class Main {
public static void main(String[] args) {
System.out.println(Animal.LEGS); // 4 (클래스명으로 접근)
}
}
모든 필드는 public static final 이므로 반드시 값을 지정해야 한다.
default 메서드
java 8 이후 인터페이스에서도 일반 메서드를 가질 수 있다.
interface Animal {
void makeSound();
// default 메서드 (구현 제공 가능)
default void sleep() {
System.out.println("Sleeping...");
}
}
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Bark! Bark!");
}
}
public class Main {
public static void main(String[] args) {
Dog myDog = new Dog();
myDog.makeSound(); // "Bark! Bark!"
myDog.sleep(); // "Sleeping..." (default 메서드 실행)
}
}

