[혼공자] 07-3. 추상 클래스

Benjamin·2023년 3월 12일
0

혼공자

목록 보기
23/27

07-3. 추상 클래스

  • 추상 (사전적 의미) = 실체 간에 공통되는 특성을 추출한 것
    ex) 새, 곤충, 물고기...의 실체에서 공통되는 특성 추출해보면 '동물'이라는 공통점이 있다.
    동물 : 실체라기보다 실체들의 공통되는 특성을 가지고있는 추상적인 것

실체 클래스 = 객체를 직접 생성할 수 있는 클래스
추상 클래스 = 실체 클래스들의 공통적인 특성을 추출해서 선언한 클래스

추상 클래스와 실체 클래스는 상속관계 : 추상 클래스가 부모, 실체 클래스가 자식
-> 실체 클래스는 추상 클래스의 모든 특성을 물려받고, 추가적인 특성을 가질 수 있다.

특성 = 필드와 메소드
예 ) Bird.class, Insect.class, Fish.class 등 실체 클래스에서 공통되는 필드와 메소드를 따로 선언한 Animal.class 클래스를 만들 수 있는데, 이것이 바로 추상 클래스이다.

추상 클래스의 용도

실체 클래스의 공통적인 특성(필드, 메소드)을 뽑아내어 추상 클래스로 만드는 이유가 무엇일까?

공통된 필드와 메소드의 이름을 통일할 목적

실체 클래스를 설계하는 사람이 여러 사람일 경우, 실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다.
데이터와 기능이 모두 동일함에도 이름이 다르다보니, 객체마다 사용 방법이 달라진다.

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

공통적인 필드와 메소드는 추상 클래스에 모두 선언해두고, 다른 점만 실체 클래스에 선언하면 실체 클래스를 작성하는데 시간을 절약할 수 있다.

예를 들어보자.

자동차를 설계할 때는 일반적인 타이어 규격에 맞춰 작성해야한다.
즉 특정한 타이어만 사용할 수 있도록 자동차를 설계하지는 않는다는 것이다.
일반적인 타이어 규격을 준수하는 타이어는 어떤것이든 부착할 수 있도록 하기 위해서이다.
여기서 타이어 규격은 타이어의 추상 클래스이고, 타이어 규격을 준수하는 한국 타이어나 금호 타이어는 타이어의 실체 클래스라고 볼 수 있다.

추상 클래스 선언

추상 클래스를 선언할 때 클래스 선언에 abstract 키워드를 붙여야한다.
이를 붙이면 new 연산자를 이용해서 객체를 만들지 못하고, 상속을 통해 자식 클래스만 만들 수 있다.

public abstract class 클래스 {
	//필드
    //생성자
    //메소드
}

추상클래스도 일반 클래스와 마찬가지로 필드, 생성자, 메소드 선언을 할 수 있다.
new 연산자로 직접 생성자를 호출할 수는 없지만 자식 객체가 생성될 때 super(...)를 호출해 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야한다.

실체 클래스 생성

추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 객체를 직접 생성해서 사용할 수 없다.
Animal animal = new Animal(); //불가능

추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용된다.
코드로 설명하면 추상 클래스는 extends뒤에만 올 수 있는 클래스이다.
class Ant extends Animal {...}

추상 메소드와 재정의

추상 클래스는 실체 클래스가 공통적으로 가져야할 필드와 메소드를 정의해놓은 추상적인 클래스로, 실체 클래스의 멤버(필드, 메소드)를 통일하는 데 목적이 있다.
모든 실체들이 가지고있는 메소드의 실행 내용이 동일하다면 추상 클래스에 메소드를 작성하는게 좋을거다.

하지만, 메소드 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우가 있다.
예를 들어, 모든 동물은 소리를 내기 때문에 Animal 추상 클래스에서 sound()메소드를 정의했다고 가정하자.
어떤 소리를 내도록 해야하는데, 동물은 다양한 소리를 내므로 실체 클래스에서 직접 작성되어야 될 부분이다.
그렇다고해서 sound()메소드를 실체 클래스에서 작성하도록 하면 sound() 메소드를 잊어버리고 작성하지 않을 경우 모든 동물은 소리를 낸다는 것에 위배된다.

이런 경우를 위해 추상 클래스에서는 추상 메소드를 선언할 수 있다.
추상 메소드는 abstract 키워드와 함께 메소드의 선언부만 있고 메소드 실행 내용인 중괄호{}가 없는 메소드를 말한다.
추상 메소드는 추상 클래스에서만 선언할 수 있다.
[public | protected] abstrac 리턴타입 메소드이름(매개변수,...);

추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록 강제하고 싶은 메소드가 있을 경우 해당 메소드를 추상 메소드로 선언한다.

자식 클래스는 반드시 추상 메소드를 재정의해서 실행 내용을 작성해야하며, 그렇지 않으면 컴파일 에러가 발생한다.

추상 메소드를 재정의하지않으면, 자식 클래스도 추상 클래스가 되어야한다.

Animal 클래스

package sec03.exam02;

public abstract class Animal { //추상클래스 
	public String kind;
	
	public void breathe() {
		System.out.println("숨을 쉽니다.");
	}
	
	public abstract void sound(); //추상메소드 
}

Dog 클래스

package sec03.exam02;

public class Dog extends Animal{
	
	public Dog() {
		this.kind = "포유류";
	}
	
	@Override //추상메소드 재정의 
	public void sound() {
		System.out.println("멍멍");
	}

}

Cat 클래스

package sec03.exam02;

public class Cat extends Animal{
	
	public Cat() {
		this.kind = "포유류";
	}
	
	@Override
	public void sound() {
		System.out.println("야용"); //추상 메소드 재정의 
	}

}

AnimalExample 클래스

package sec03.exam02;

public class AnimalExample {

	public static void main(String[] args) {
		Dog dog = new Dog();
		Cat cat = new Cat();
		
		dog.sound();
		cat.sound();
		System.out.println("------");
		
		//변수의 자동 타입 변환 
		Animal animal = null;
		animal = new Dog();
		animal.sound(); //자동 타입 변환 및 재정의 된 메소드 호출 
		animal = new Cat();
		animal.sound(); //자동 타입 변환 및 재정의 된 메소드 호출 
		System.out.println("------");
		
		//메소드의 다형성
		animalSound(new Dog()); //자동 타입 변환 
		animalSound(new Cat()); //자동 타입 변환 
	}
	
	public static void animalSound(Animal animal) {
		animal.sound(); //재정의된 메소드 호출 
	}

}

sound() 메소드를 호출하는 방법을 세가지로 표현해봤다.

  1. 가장 일반적인 방식으로 Dog, Cat 변수로 호출한다.
  2. Animal 변수로 타입 변환해서 sound()메소드 호출한다.
    자식은 부모 타입으로 자동 타입변환 될 수 있고, 메소드가 재정의 되어있을 경우 재정의된 자식 메소드가 호출되는 다형성의 특징이 적용된다.
  3. 부모 타입의 매개변수에 자식 객체를 대입해 메소드의 다형성을 적용한다.

0개의 댓글