CodeGym /행동 /JAVA 25 SELF /다형성과 추상 클래스의 관계

다형성과 추상 클래스의 관계

JAVA 25 SELF
레벨 18 , 레슨 4
사용 가능

1. 추상 클래스와 메서드

살다 보면(프로그래밍에서도) 이렇게 말하고 싶을 때가 있습니다: “정확히 어떻게 하는지는 모르겠지만, 반드시 있어야 한다는 건 알아!” 예를 들어, 모든 동물은 소리를 낼 수 있어야 하지만 어떤 소리인지는 동물마다 다릅니다. 바로 이런 경우를 위해 Java에는 추상 클래스추상 메서드가 있습니다.

추상 클래스는 직접 인스턴스를 만들 수 없는 클래스입니다(Animal이 추상 클래스라면 new Animal()를 쓸 수 없음). 하지만 이 클래스를 상속받을 수는 있습니다. 추상 클래스는 일반(구현된) 메서드와 추상 메서드를 함께 포함할 수 있습니다. 추상 메서드는 선언만 되어 있고 구현은 없습니다.

추상 메서드는 메서드 본문이 없는 메서드입니다. abstract 키워드로 선언하며, 하위 클래스에서 반드시 구현해야 합니다(하위 클래스 자체가 추상 클래스인 경우는 예외).

실생활 예

동물원을 위한 애플리케이션이 있다고 해봅시다. 모든 동물에 makeSound() 메서드가 있기를 원하지만, 어떤 소리를 내는지는 모릅니다. 그럴 때 추상 클래스를 만듭니다:

public abstract class Animal {
    public abstract void makeSound(); // 추상 메서드
}

그리고 구체적인 동물들이 각자 방식으로 이 메서드를 구현합니다:

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

이제 누군가 new Animal()을 만들려고 하면, 컴파일러는 곧바로 이렇게 말할 것입니다: “미안하지만, 추상 동물은 자연에 존재하지 않아!” 이것은 유용합니다. 프로그램에는 구체적인 동물, 구체적인 동작만 존재하도록 보장할 수 있으니까요.

2. 추상을 통한 다형성

추상화는 객체 집합을 위한 공통 인터페이스를 도출하는 것입니다. 추상 클래스는 바로 그 공통 인터페이스를 규정합니다. 즉, 모든 하위 클래스가 반드시 구현해야 하는 메서드를 지정합니다.

다형성과 추상화는 함께 작동합니다. 추상 클래스는 모든 하위 클래스에 필요한 메서드가 있음을 보장하고, 다형성은 상위 타입 참조를 통해 그 메서드들을 호출할 수 있게 해 줍니다.

예: 동물원 만들기

작은 동물원을 만들어 봅시다. 추상 클래스 Animal과 그 하위 클래스 몇 개가 있습니다:

public abstract class Animal {
    public abstract void makeSound();
}
public class Cow extends Animal {
    @Override
    public void makeSound() {
        System.out.println("음메!");
    }
}
public class Duck extends Animal {
    @Override
    public void makeSound() {
        System.out.println("꽥꽥!");
    }
}

이제 동물 배열을 만들 수 있습니다:

Animal[] zoo = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Duck()
};

for (Animal animal : zoo) {
    animal.makeSound(); // 각 동물에 대해 "올바른" 메서드가 호출된다
}

배열의 각 객체는 구체적인 동물이지만, 코드 입장에서는 그냥 Animal입니다. 추상화와 다형성 덕분에 각 객체에 makeSound() 메서드가 존재하며 올바르게 동작함을 확신할 수 있습니다.

3. 다형성을 위한 추상 클래스 활용

좀 더 실용적인 예를 보겠습니다. 어떤 회사의 직원 관리를 위한 애플리케이션을 만든다고 가정합시다. 직원 유형은 매니저, 개발자, 테스터 등 다양합니다. 모두 공통 메서드 work()를 갖지만, 수행 방식은 서로 다릅니다.

추상 클래스 Employee

public abstract class Employee {
    protected String name;

    public Employee(String name) {
        this.name = name;
    }

    public abstract void work();
}

구체 하위 클래스

public class Manager extends Employee {
    public Manager(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println(name + " — 팀을 이끈다.");
    }
}

public class Developer extends Employee {
    public Developer(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println(name + " — 코드를 작성한다.");
    }
}

public class Tester extends Employee {
    public Tester(String name) {
        super(name);
    }

    @Override
    public void work() {
        System.out.println(name + " — 애플리케이션을 테스트한다.");
    }
}

다형성 사용

이제 직원 배열을 만들고 각자에게 work()를 호출할 수 있습니다:

Employee[] employees = {
    new Manager("안나"),
    new Developer("이반"),
    new Tester("마리아")
};

for (Employee e : employees) {
    e.work();
}

결과:

안나 — 팀을 이끈다.
이반 — 코드를 작성한다.
마리아 — 애플리케이션을 테스트한다.

주의: 우리는(그리고 알 필요도 없습니다!) 반복문에서 정확히 어떤 직원 타입인지는 모릅니다. 그냥 work()를 호출하면, 각 객체가 자기 할 일을 수행합니다.

4. 유용한 포인트

메서드 구현 보장
추상 클래스는 모든 하위 클래스가 필요한 메서드를 구현하도록 강제합니다. 하위 클래스에서 추상 메서드 구현을 빠뜨리면, 컴파일러가 곧바로 말할 것입니다: “반드시 구현해야 해!”

범용 인터페이스
추상 타입(Employee[], List<Animal>)의 배열이나 리스트로 동작하는 코드는 완전히 범용적일 수 있습니다. 새로운 하위 클래스를 추가해도 핵심 코드를 변경할 필요가 없습니다.

엉뚱한 객체로부터의 보호
추상 클래스는 직접 인스턴스화할 수 없기 때문에, 필요한 메서드를 구현하지 않은 “정체불명” 타입의 객체가 실수로 만들어질 일이 없습니다.

이론과 문법: 추상 클래스/메서드 선언 방법

  • class 앞에 abstract 키워드를 붙이면 추상 클래스를 선언합니다.
  • abstract 키워드로 추상 메서드를 선언하며, 본문 없이(세미콜론만) 선언합니다.
  • 하나라도 추상 메서드가 있으면 그 클래스는 반드시 추상 클래스여야 합니다.
  • 추상 클래스를 상속하는 클래스는 모든 추상 메서드를 구현해야 하며, 그렇지 않다면 그 클래스 자체도 추상이어야 합니다.

도식

public abstract class Animal {
    public abstract void makeSound();
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("야옹!");
    }
}

5. 추상 클래스를 다룰 때 흔한 실수

오류 №1: 추상 클래스의 인스턴스를 만들려고 함.
new Animal() 같은 코드는 컴파일되지 않습니다. 추상 클래스는 부품 없이 가구 조립 설명서를 보는 것과 같습니다. 구체 하위 클래스가 나타나기 전에는 객체를 만들 수 없습니다.

오류 №2: 하위 클래스에서 추상 메서드 구현을 누락.
추상 메서드를 선언해 놓고 하위 클래스에서 구현하지 않았다면(그리고 그 클래스도 추상이 아니라면), 컴파일러가 오류를 보고합니다.

오류 №3: 접근 제한자를 깜빡함.
재정의된 메서드는 상위 클래스보다 더 엄격한 접근 제한자를 가질 수 없습니다. 예를 들어, 추상 메서드가 public이었다면 구현도 반드시 public이어야 합니다(protectedprivate가 아님).

오류 №4: 본문이 있는 추상 메서드를 시도함.
abstract 메서드는 본문을 가질 수 없습니다. 그렇지 않으면 컴파일러가 말할 것입니다: “추상으로 할지, 구현할지 하나만 정해!”

오류 №5: 정적 메서드에는 다형성이 적용되지 않음.
다형성은 인스턴스 메서드에만 동작합니다. 정적 메서드는 오버라이드되지 않고 숨겨질 뿐이므로, 호출 시 동작은 실제 객체가 아니라 변수의 타입에 따라 결정됩니다.

1
과제
JAVA 25 SELF, 레벨 18, 레슨 4
잠금
그래픽 편집기 기초: 추상 클래스와 메서드 선언
그래픽 편집기 기초: 추상 클래스와 메서드 선언
1
과제
JAVA 25 SELF, 레벨 18, 레슨 4
잠금
반려동물에 생명을 불어넣기: 상속과 추상 메서드 구현
반려동물에 생명을 불어넣기: 상속과 추상 메서드 구현
1
과제
JAVA 25 SELF, 레벨 18, 레슨 4
잠금
통합 팀: 추상 클래스의 다형성
통합 팀: 추상 클래스의 다형성
1
과제
JAVA 25 SELF, 레벨 18, 레슨 4
잠금
동적 농장: 추상 클래스, 필드 및 다형성
동적 농장: 추상 클래스, 필드 및 다형성
1
설문조사/퀴즈
폴리모르피즘 и перегрузка, 레벨 18, 레슨 4
사용 불가능
폴리모르피즘 и перегрузка
폴리모르피즘 и перегрузка
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION