[Java] 추상 클래스

·2024년 7월 5일
0

Java

목록 보기
6/9
post-thumbnail

추상 클래스란?

사전적 의미로 추상(abstract)은 실체 간에 공통되는 특성을 추출한 것을 말한다. 추상 클래스는 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.

추상 클래스와 실체 클래스는 상속의 관계를 가지고 있으며, 추상 클래스가 부모이고 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있다.

이렇게 말로만 설명하면 이해가 어려울 수 있으니, 예시를 보자.


위의 예시들을 보면 어떤 느낌인지 대충 감이 올 것이다.

그러면 또 의문이 생긴다. 왜 굳이 추상 클래스를 사용하는 걸까?

추상 클래스의 용도

  1. 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적

    실체 클래스를 개발하는 사람이 여러명일 경우, 필드와 메소드가 제각기 다른 이름을 가질 수 있다. 동일한 데이터와 기능을 갖지만 이름이 달라서 사용 방법이 달라지는 것을 방지한다.

  2. 실체 클래스를 작성할 때 시간을 절약

    공통적인 필드와 메소드가 있을 수 있는데, 이것은 추상 클래스에 선언해두고 다른 것은 실체 클래스에 직접 구현하여 시간을 절약한다.

한 마디로 추상 클래스는 설계의 기능을 한다고 생각하면 좋다.

추상 클래스의 선언

추상 클래스를 선언할 때는 클래스 선언에 abstract 키워드를 붙인다. 이 키워드를 사용하면 new 연산자를 통해 객체를 만들 수 없다. 하지만 상속받은 자식 클래스에서 super()를 호출하여 객체를 생성하므로 추상 클래스도 반드시 생성자가 있어야한다.

abstract class Animal {
		
    public String classification;

    public Animal(String classification) {
        this.species = species;
    }

    public abstract void sound();
    public abstract void move();
    
    public void sleep() {
	    System.out.println("잔다");
	  }
}

모든 실체 클래스에서 동일한 실행 내용을 갖는 메소드는 추상 클래스에 작성한다. sleep()이 그 경우이다.

그러면 sound()를 생각해보자. 동물은 소리를 낸다. 하지만 강아지는 “월월” 혹은 “멍멍”하고 짓는다. 새는 “짹짹”하고 운다. 동물은 소리를 내지만, 각 동물들은 다른 소리를 내며 운다. 이럴 경우에 사용하는 것이 오버라이딩(재정의)이다.

추상 메소드와 오버라이딩

동물은 소리를 내기 때문에 sound()라는 메소드가 있어야하지만, 다른 소리를 내므로 실체 클래스에서 메소드를 작성하여야 한다. 잊어버리지 않고 실체 클래스에서 sound()를 작성하기 위해 사용하는 것이 추상 메소드이다.

하위 클래스가 반드시 실행 내용을 채우도록 하고 싶은 메소드가 있다면, 해당 메소드를 추상 메소드로 선언하면 된다. 그럼 아래와 같이 반드시 추상 메소드를 오버라이딩(재정의)하여 실행 내용을 작성해야한다. 하지 않으면 컴파일 에러가 난다.

class Dog extends Animal {
    public Dog(String classification) {
        this.classification = "mammal";
    }

    @Override
    public void sound() {
        System.out.println("월월!");
    }

    @Override
    public void move() {
        System.out.println("네 발로 걷기");
    }
}
class Bird extends Animal {
    public Bird(String classification) {
        this.classification = "bird";
    }

    @Override
    public void sound() {
        System.out.println("짹짹");
    }

    @Override
    public void move() {
        System.out.println("날아가기");
    }
}

이때, 각 객체의 sound를 호출하는 방법은 3가지가 있다.

  1. 일반적인 방법

    public class AnimalExample {
    	public static void main(String args) {
    		Dog dog = new Dog();
    		Bird bird = new Brid();
    		
    		dog.sound();
    		bird.sound();
    	}
    }
  2. 부모 타입 변수

    public class AnimalExample {
    	public static void main(String args) {
    		Animal animal = null;
    		animal = new Dog();
    		animal.sound(); // 월월!
    		animal = new Bird();
    		animal.sound(); // 짹짹
    	}
    }

    자식 타입은 부모 타입으로 자동 타입 변환이 될 수 있다. 메소드가 오버라이딩되어 있을 경우 오버라이딩된 자식 메소드가 호출된다.

  3. 부모 타입 매개변수

    public class AnimalExample {
    	public static void main(String args) {
    		animalSound(new Dog()); // 월월!
    		animalSound(new Bird()); // 짹짹
    	}
    	
    	private static void animalSound(Animal animal) {
    		animal.sound();
    	}
    }

    두 번째와 같은 원리이다.

추상 클래스는 객체 지향 프로그래밍에서 중요한 개념으로, 공통된 속성과 메서드를 정의하여 코드의 재사용성과 유지보수성을 높여준다. 개념을 잘 이해하고 적절히 활용할 수 있도록 하자.

이 포스팅은 신용권, ⌜이것이 자바다-신용권의 Java 프로그래밍 정복⌟, 한빛미디어(주) 책을 참고했습니다.

profile
개발블로그👩🏻‍💻

0개의 댓글