고래씌
[JAVA] 10-3. 다형성(추상클래스 abstract 와 인터페이스) 본문
1. 추상클래스
- 미완성된 클래스 abstract class
- 객체생성 불가능(단, 참조변수(레퍼런스 변수)로는 선언 가능)
- 추상클래스 내부에 추상메소드가 존재하는 순간 해당 클래스는 반드시 추상클래스로 정의
(일반필드 + 일반 메소드 + [추상메소드(생략가능)])
※ 단, 추상메소드가 굳이 없어도 추상클래스로 둘 수 있다.
언제? ① 클래스가 아직 구체적으로 덜 구현된 상태인 것으로 보이는 경우(개념적)
② 현재 이 클래스를 객체 생성이 불가하게끔 하고자 할 때(기술적)
=> 객체 생성은 불가능한데 참조변수로 선언 가능하다라는 특징은 다형성을 적용할 수 있다로 해석이 됨.
- 몸통부가 존재하지 않는 미완성 메소드 == 추상 메소드
- 몸통부가 없는 미완성 메소드를 정의하고자 하면 abstract 예약어를 사용해야한다.
=> 미완성 메소드가 하나라도 현재 클래스에 포함되는 순간, 해당 클래스 또한 미완성 클래스가 되어버린다.
따라서, 클래스명 앞에도 abstract 예약어를 적어줘야한다.



=> 미완성된 클래스인 추상클래스를 상속받게되면, 부모클래스에 있는
미완성된 메소드(추상메소드)를 강제로 오버라이딩 해줘서 완성시켜야함

=> 추상클래스는 객체 생성이 불가능하다! 미완성 클래스이기 때문.
=> 단, 객체생성은 불가능하지만, 참조변수로는 사용 가능!
=> 다형성을 적용해서 자식객체를 생성하고 이를 저장하는 용도로 사용이 가능하다!


2. 추상메소드
- 미완성된 메소드로 몸통부{}가 구현되어 있지 않은 메소드
- 자식클래스에서 오버라이딩을 통해 완성됨(강제로 오버라이딩 해야함)
=> 오버라이딩 하지 않을 경우 에러가 발생
=> 메소드 사용의 통일성 확보 목적
=> 표준화된 틀을 제공할 수 있는 목적
3. 인터페이스
- 인터페이스
[표현법]
접근제한자 interface 인터페이스명 {}
- 상수필드와 추상메소드로만 이루어진 추상 클래스의 변형체다!
- 메소드 통일성을 부여하기 위해 추상 메소드만 따로 모아놓은 것으로 상속시 인터페이스 내에 정의된 모든 추상메소드 구현해야함
- 인터페이스에서 선언한 필드는 명시하지 않아도 무조건 상수필드로 사용됨
- 아래와 같이 "stactic final" 을 붙이지 않아도 무조건 상수로 사용되는 것을 확인

- 인터페이스에서 선언한 메소드는 명시하지 않아도 무조건 추상메소드이다.
- 인터페이스에서는 추상메소드만 정의할 수 있기 때문에 메소드의 몸통부 작성이 불가능하며, abstract 키워드가 자동으로 추가됨.
ex)
pulibc void eat() { => 에러 발생
}
void eat(); => O

- 무조건 구현해야하는 메소드가 존재할 경우 인터페이스를 만들어서 상속하게 한다.
- 인터페이스는 ★다중 상속을 허용한다. 참고)일반 클래스는 다중 상속 X
=> 결국 메소드에 정의만 하고 있는게 인터페이스이기 때문에, 여러 메소드가 겹치더라도 최종 구현은 구현클래스(자식클래스)에서 이루어질 것이기 때문에 다중 상속(구현)을 받아도 문제가 없다. (인터페이스에서는 상속을 구현이라고 함)
- 추상 클래스와 다르게 강한 규칙성과 강제성을 가짐
(1) ★공통점
① 객체 생성은 안되나, 참조변수로서 사용이 가능함.(즉, 다형성을 적용할 수 있다)
② 상속(구현)하는 클래스에 추상메소드를 구현하도록 강제한다.
(2) ★차이점
① 추상클래스는 클래스 내에 인스턴스 변수, 메소드를 생성이 가능하고, 추상메소드가 포함되어있거나 abstract 키워드로 클래스가 정의되어 있고
② 인터페이스는 인스턴스 변수, 일반 메소드 생성이 불가능하며 모든 변수는 상수필드, 모든 메소드는 추상메소드로 정의되어 있다.
③ ★★★존재하는 목적이 다르다★★★
- 추상클래스는 추상클래스를 상속받아서 기능을 이용하고, 클래스를 "상속"하는데 목적이 있음
- 인터페이스는 클래스의 기능(함수)구현을 강제하기 위해 사용됨. 즉, 기능구현을 강제함으로써 인터페이스를 상속받은 모든 클래스에 동일한 동작을 보장할 수 있음
(3) extends와 implements
- 클래스 간에 상속 관계일 때 : 클래스명 extends 부모클래스명
- 클래스와 인터페이스의 구현 관계일 때 : 클래스명 implements 인터페이스명, 인터페이스명 ...
- 인터페이스간의 상속 관계일 때 : 인터페이스명 extends 인터페이스명, 인터페이스명
※ 정리
▶ 클래스에서 클래스를 상속 받을 때 : extends 클래스(단일상속만 가능) : 화살표 실선
▶ 클래스에서 인터페이스를 구현할 때 : implements 인터페이스, 인터페이스...(다중구현 가능) : 화살표 점선
▶ 인터페이스에서 인터페이스를 상속 : extends 인터페이스, 인터페이스..(다중상속 가능) : 화살표 실선
추상클래스 | 인터페이스 | |
상속개수 | 단일상속 | 다중상속 |
키워드 | extends | implements |
추상메소드 표현법/개수 | 추상메소드 0개 이상 명시적 abstract 기술 | 모든 메소드가 추상메소드 묵시적으로 abstract 기술 |
일반메소드 | O | X |
필드 | 일반필드 가질 수 있음 | 상수필드만 가질 수 있음(묵시적 static final) |
<배운순서>
extends 일반클래스 → extends 추상클래스 → implements 인터페이스
---------------------------------------------------------------------------------------------->
뒤로 갈수록 기능 구현의 강제성이 더 짙어진다.
1) 인터페이스 적용 전
<추상클래스 Person>
package com.kh.chap02_abstractAndInterface.part02_family.model.vo;
public abstract class Person {
private String name;
private double weight;
private int health;
public Person() {
}
public Person(String name, double weight, int health) {
super();
this.name = name;
this.weight = weight;
this.health = health;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
@Override
public String toString() {
return "Person [name=" + name + ", weight=" + weight + ", health=" + health + "]";
}
public abstract void eat();
public abstract void sleep();
}
<자식클래스 Mother 클래스>
package com.kh.chap02_abstractAndInterface.part02_family.model.vo;
public class Mother extends Person{
private String babyBirth; // 아기의 탄생 여부 : 출산, 입양, 없음
public Mother() {
}
public Mother(String name, double weight, int health, String babyBirth) {
super(name, weight, health);
this.babyBirth = babyBirth;
}
public String getBabyBirth() {
return babyBirth;
}
public void setBabyBirth(String babyBirth) {
this.babyBirth = babyBirth;
}
@Override
public String toString() {
return "Mother [babyBirth=" + babyBirth + ", toString()=" + super.toString() + "]";
}
@Override
public void eat() {
// 엄마가 밥을 먹으면?
// 몸무게 10 증가
super.setWeight(super.getWeight()+10); // 수정할 몸무게는 기존의 몸무게 + 10
// 건강도 10 감소
super.setHealth(super.getHealth()-10);
}
@Override
public void sleep() {
// 건강도 10 증가
super.setHealth(super.getHealth()+10);
}
}
<자식클래스 Baby 클래스>
package com.kh.chap02_abstractAndInterface.part02_family.model.vo;
public class Baby extends Person{
public Baby() {
}
public Baby(String name, double weight, int health) {
super(name, weight, health);
}
@Override
public String toString() {
return "Baby [toString()=" + super.toString() + "]";
}
// eat -> 몸무게 3증가, 건강도 1증가
@Override
public void eat() {
super.setWeight(super.getWeight()+3);
super.setHealth(super.getHealth()+1);
}
// slepp -> 건강도 3증가
@Override
public void sleep() {
super.setHealth(super.getHealth()+3);
}
}
<main 메소드가 포함된 Run 클래스>
package com.kh.chap02_abstractAndInterface.part02_family.run;
import com.kh.chap02_abstractAndInterface.part02_family.model.vo.Baby;
import com.kh.chap02_abstractAndInterface.part02_family.model.vo.Mother;
import com.kh.chap02_abstractAndInterface.part02_family.model.vo.Person;
public class Run {
public static void main(String[] args) {
// 인터페이스 적용 전
// Person p = new Person(); // 에러 발생. 미완성 클래스니까(추상클래스)
Person p1 = new Mother("범고래", 50, 50, "출산"); // 상속구조에서만 업캐스팅이 발생한다
Person p2 = new Baby("이고래", 3.5, 60);
System.out.println(p1);
System.out.println(p2);
p1.eat(); // Mother 60 40
p1.sleep(); // Mother 60 50
p2.sleep(); // Baby 6.5 61
p2.eat(); // 6.5 64
System.out.println("== 다음날 ==");
System.out.println(p1);
System.out.println(p2);
}
}

=> 추상클래스는 자식클래스를 상속하는데 목적!
2) 인터페이스 적용 후





'JAVA > JAVA 기초' 카테고리의 다른 글
[JAVA] 11-1. 기본 API(1) (Math 클래스, 문자열) (0) | 2023.10.18 |
---|---|
[JAVA] 다형성(추상 클래스, 인터페이스 실습) (0) | 2023.10.18 |
[JAVA] 10-2. 다형성 객체 배열 실습 2(Book객체) (0) | 2023.10.17 |
[JAVA] 10-1. 다형성 실습 (0) | 2023.10.17 |
[JAVA] 10. 다형성 (0) | 2023.10.16 |