실체 클래스 : 객체를 직접 생성할 수 있는 클래스
추상 클래스 : 실체 클래스들의 공통적인 특성을 추출해서 선언한 클래스
→ 추상 클래스와 실체 클래스는 상속의 관계를 가지고 있음
→ 추상 클래스가 부모, 실체 클래스가 자식으로 구현되어
실체 클래스는 추상 클래스의 모든 특성(필드, 메소드)을 물려받고,
추가적인 특성을 가질 수 있음
→ Bird.class, Insect.class, Fish.class 등의 실체 클래스에서
공통되는 필드와 메소드를 따로 선언한
Animal.class 클래스(추상 클래스)를 만들 수 있음
- 실체 클래스의 공통적인 특성(필드, 메소드)을 뽑아내어
추상 클래스로 만드는 이유
1. 공통된 필드와 메소드의 이름을 통일할 목적
ex)
실체 클래스를 설계하는 사람이 여러 사람일 경우,
실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있음
· 소유자의 이름을 저장하는 필드의 경우
Telephone 클래스 → owner
SmartPhone클래스 → use
· 전원을 켜는 메소드의 경우
Telephone → turnOn()
SmartPhone → powerOn()
이렇게 데이터와 기능이 모두 동일함에도 불구하고
이름이 다르다 보니, 객체마다 사용 방법이 달라짐
이 방법보다는 Phone이라는 추상 클래스에
소유자인 owner필드와 trunOn() 메소드를 선언하고,
Telephone과 SmartPhone은 Phone을 상속함으로써
필드와 메소드 이름을 통일할 수 있음
2. 실체 클래스를 작성할 때 시간 절약
ex)
공통적인 필드와 메소드는 추상 클래스인 phone에 모두 선언해두고,
다른 점만 실체 클래스에 선언하면 실체 클래스를 작성하는 데 시간을 절약할 수 있음
Telephone과 SmartPhone은 Phone을 상속받기 때문에
owner필드와 turnOn() 메소드를 선언할 필요가 없음
Telephone과 SmartPhone의 추가적인 특성인
autoAnswering()과 internetSearch()메소드만 각각 선언하면 됨
public abstract class 클래스 {
//필드
//생성자
//메소드
}
: 추상 클래스를 선언할 때에는
클래스 선언에 abstract 키워드를 붙여야 함
: abstract를 붙이면 new 연산자를 이용해서 객체를 만들지 못함
상속을 통해 자식 클래스만 만들 수 있음
: new 연산자로 직접 생성자를 호출할 수는 없지만
자식 객체가 생성될 때 super(···)를 호출해서
추상 클래스 객체를 생성하므로
추상 클래스도 생성자가 반드시 있어야함
👩💻 추상 클래스
//추상클래스
abstract class Phone{
//필드
public String owner;
//생성자
public Phone(String owner) {
this.owner = owner;
}
//메소드
public void turnOn() {
System.out.println("폰 전원을 켭니다.");
}
public void turnOff() {
System.out.println("폰 전원을 끕니다.");
}
}
//실체클래스
class SmartPhone extends Phone{
//생성자
public SmartPhone(String owner) {
super(owner);
}
//메소드
public void internetSearch() {
System.out.println("인터넷 검색을 합니다.");
}
}
//실행클래스
public class PhoneExample {
public static void main(String[] args) {
//Phone의 생성자를 호출해서 객체를 생성할 수 없음
//Phone phone = new Phone();
//SmartPhone으로 객체를 생성해서
//Phone의 메소드인 turnOn(), turnOff()메소드 사용
SmartPhone smartPhone = new SmartPhone("홍길동");
smartPhone.turnOn();
smartPhone.internetSearch();
smartPhone.turnOff();
}
}
💻 결과
폰 전원을 켭니다.
인터넷 검색을 합니다.
폰 전원을 끕니다.
- 추상 클래스는 실체 클래스의 공통되는 필드와 메소드를
추출해서 만들었기 때문에 객체를 직접 생성해서 사용할 수 없음
Animal animal = new Animal(); [x]
- 추상 클래스는 새로운 실체 클래스를 만들기 위해 부모 클래스로만 사용됨
추상 클래스는 extends 뒤에만 올 수 있는 클래스임
class Ant extends Animal {···} [o]
- 추상 클래스
: 실체 클래스가 공통적으로 가져야 할 필드와 메소드들을
정의해놓은 추상적인 클래스
- 실체 클래스
: 멤버(필드,메소드)를 통일하는데 목적
- 모든 실체들이 가지고 있는 메소드의 실행 내용이 동일하다면
추상 클래스에 메소드를 작성하는 것이 좋음
- 메소드의 선언만 통일하고, 실행 내용은 실체 클래스마다 달라야 하는 경우
ex)
Animal 추상 클래스에 sound()라는 메소드 정의 할때
실체 클래스에서 직접 작성해야 될 부분임
왜냐하면 동물은 다양한 소리를 내므로
이것을 추상 클래스에서 통일적으로 작성할 수 없기 때문
[public | protected] abstract 리턴타입 메소드이름(매개변수, ···);
: 추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록
강제하고 싶은 메소드가 있을 경우
해당 메소드를 추상 메소드로 선언함
ex)
sound()메소드를 추상 메소드로 선언
public abstract class Animal {
public abstract void sound();
}
Animal 클래스를 상속하는 하위 클래스는 동물마다
고유한 소리를 내도록 sound()메소드를 재정의 해야함
Dog는 "멍멍", Cat은 "야옹" 소리를 내도록
Dog와 Cat 클래스에서 sound() 메소드를 재정의.
👩💻추상 메소드 선언
//추상 클래스
abstract class Animal{
public String kind;
public void breath() {
System.out.println("숨을 쉽니다.");
}
//추상 메소드
public abstract void sound();
}
//추상 메소드 재정의
class Dog extends Animal{
public Dog() {
this.kind = "포유류";
}
//재정의
@Override
public void sound() {
System.out.println("멍멍");
}
}
class Cat extends Animal{
public Cat() {
this.kind = "포유류";
}
//재정의
@Override
public void sound() {
System.out.println("야옹");
}
}
//실행 클래스
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();
}
}
💻 결과
멍멍
야옹
-----------
멍멍
야옹
-----------
멍멍
야옹