Java/Java

상속_추상 클래스

이게뭐여 2022. 2. 26. 16:17

1. 실체 클래스와 추상 클래스

실체 클래스는 그 클래스를 통해 객체를 직접 생성할 수 있는 클래스를 말한다.

추상 클래스란 여러 실체 클래스의 공통적인 특성(필드, 메소드)을 추출하여 선언해놓은 클래스를 말한다.

실체 클래스는 추상 클래스를 상속하여 추상 클래스에 선언된 공통적인 특성을 물려받고, 각자 추가적인 특성을 가질 수 있다.

 

추상 클래스를 사용하는 목적은 크게 실체 클래스들의 통일성 확보, 코딩의 효율성으로 볼 수 있다.

만약 여러 사람이 추상 클래스 없이 실체 클래스를 작성한다고 가정해보자.

각 실체 클래스들이 다루는 데이터와 기능이 동일하다고 해도, 실체 클래스마다 멤버의 명칭, 사용방법이 다르다면 기능을 구현함에 있어 혼란과 오류를 초래할 수 있다.

또한 추상 클래스에 공통적인 특성을 미리 선언해 둔다면, 각 실체 클래스에는 고유한 특성만 작성해주면 되기 때문에 코딩의 효율을 높일 수 있다.

 

 

2. 추상 클래스 선언

추상 클래스를 선언하기 위해서는 아래와 같이 abstract 키워드를 사용해야한다.

  • public abstract class 클래스명 {};

만약 위와 같이 추상 클래스로 선언된다면 해당 클래스로는 객체를 생성할 수 없고, 실체 클래스를 통해서 객체를 생성해야한다.

 

추상 클래스도 일반적인 클래스와 마찬가지로 필드, 생성자, 메소드를 선언할 수 있다.

주의 깊게 알아둬야할 점은 추상 클래스 자체가 객체를 직접 생성할 수는 없지만, 실체 클래스로 객체를 생성할 때 super()메소드를 통해 추상 클래스의 생성자가 호출 되어야 하므로 추상 클래스도 생성자가 반드시 필요하다는 것이다.

 

아래의 예제 코드는 추상 클래스 선언의 예를 보여준다.

Phone클래스는 추상 클래스이며 필드, 생성자, 메소드가 선언되어 있다.

SmartPhone클래스는 Phone클래스를 상속하는 실체 클래스이다. 해당 클래스의 생성자 내부를 보면, super(owner);를 통해 추상 클래스의 생성자를 호출하는 것을 볼 수 있다.

또한 Phone phone = new Phone();을 통해 객체를 생성할 수 없으며, 실체 클래스를 통해서만 객체를 생성할 수 있음을 보여준다.

package sec03.exam01;

public abstract class Phone {
	//필드
	public String owner;
	
	//생성자
	//추상클래스는 new 연산자를 통해 생성자를 직접 호출할 수 없지만, 자식 클래스에서 super()를 통해 추상클래스의 생성자를 호출하므로 생성자가 필요하다.
	public Phone(String owner) {
		this.owner = owner;
	}
	
	//메소드
	public void turnOn() {
		System.out.println("폰 전원을 켭니다.");
	}
	
	public void turnOff() {
		System.out.println("폰 전원을 끕니다.");
	}

}
package sec03.exam01;

public class SmartPhone extends Phone {
	//생성자
	public SmartPhone(String owner) {
		super(owner);
	}
	
	//메소드
	public void internetSearch() {
		System.out.println("인터넷 검색을 합니다.");
	}

}
package sec03.exam01;

public class PhoneExample {

	public static void main(String[] args) {
		//추상클래스는 new 연산자를 통해 직접 객체를 생성할 수 없다.
		//Phone phone = new Phone();
		
		SmartPhone smartPhone = new SmartPhone("kmk");
		
		smartPhone.turnOn();
		smartPhone.internetSearch();
		smartPhone.turnOff();

	}

}

 

 

3. 추상 메소드와 재정의

추상 클래스에 메소드를 선언할 때, 실체 클래스들이 메소드의 선언만 공유하고 실행 내용은 다르게 할 필요가 있을 수 있다.

이 때 사용하는 것이 추상 메소드이다. 추상 메소드는 아래와 같이 abstract와 함께 메소드 선언부만 작성하고, 메소드의 실행 내용인 {}는 없는 메소드를 말한다. 추상 메소드는 하위 클래스에서 실행 내용을 반드시 작성해줘야하며, 그렇지 않으면 컴파일 에러가 발생한다.

  • public abstract 리턴타입 메소드명(매개변수, ...);

 

아래의 예제 코드는 추상 클래스인 Animal클래스, 실체 클래스인 Dog클래스, Cat클래스를 통해 추상 메소드의 사용 예를 보여준다.

Animal클래스에는 kind필드, breath()메소드, sound()추상 메소드가 선언되어있다.

실체 클래스인 Dog클래스, Cat클래스에는 추상 메소드인 sound()가 실행 내용을 포함하여 재정의 되어있다.

package sec03.exam02;

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

}
package sec03.exam02;

public class Dog extends Animal {
	public Dog() {
		this.kind = "포유류";
	}
	
	//추상메소드는 재정의를 반드시 해야한다. 그렇지 않으면 컴파일 에러가 발생한다.
	@Override
	public void sound() {
		System.out.println("멍멍");
	}

}
package sec03.exam02;

public class Cat extends Animal {
	public Cat() {
		this.kind = "포유류";
	}
	
	//추상메소드는 반드시 재정의 되어야한다. 그렇지 않으면 컴파일 에러가 발생한다.
	@Override
	public void sound() {
		System.out.println("야옹");
	}
	

}
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("_________________________");
		
		//변수의 자동타입변환
		//자식 클래스 객체(dog, cat)가 부모 클래스 타입으로 자동변환되어 저장된다. 이럴 경우, 자식 클래스에서 재정의된 메소드가 호출된다.
		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();
	}
}

 

 

출처: 혼자 공부하는 자바(신용권)