[Java] 09_다형성(추상 클래스와 인터페이스)

2022. 8. 10. 11:28·📗 self-study/📗 KH정보교육원 당산지원

09_다형성(Polymorphism)

 

 

Sports 클래스 (== 부모 클래스)

package com.kh.chap02.abstractAndInterface.part01.basic.model.vo;

// public class Sports {
public abstract class Sports { // 추상 클래스(abstract 키워드)
	
	// 필드부
	private int people; // 스포츠에 참여하는 선수 명 수
	
	// 생성자부
	public Sports() {
		
	}
	
	public Sports(int people) {
		this.people = people;
	}
	
	// 메소드부
	// getter/setter, toString() 오버라이딩, 규칙을 출력하는 public void rule 메소드
	
	public int getPeople() {
		return people;
	}
	
	public void setPeople(int people) {
		this.people = people;
	}
	
	@Override
	public String toString() {
		return "people: " + people;
	}
	
	// 규칙을 출력하는 public void rule() 메소드
	/*
	public void rule() {
		System.out.println("규칙을 잘 지켜서 플레이하세요"); // Sports 라고 포괄적으로 표현했을 때 정확한 룰이 없음
	}
	*/
	
	// 아니 어차피 자식 클래스가 지 입맛대로 메소드 바꿀 것 같으면 부모 클래스에서는 그냥
	
	// public void rule(); // 이렇게 쓰면 안 되나?
	// This method requires a body instead of a semicolon 오류 뜸
	
	public abstract void rule();
	// The abstract method rule in type Sports can only be defined by an abstract class: abstract 클래스 내에서만 정의될 수 있다는 내용으로 오류 메시지 바뀜


}

몸통부가 존재하지 않는 미완성된 메소드 == 추상 메소드
단, 추상 메소드를 정의하고자 하다면 표현상 abstract 라는 예약어를 추가해 줘야 함
 
미완성된 추상 메소드가 하나라도 포함되는 순간 해당 클래스 또한 미완성된 클래스 (추상 클래스)가 되어 버림
 
추상 클래스 또한 예약어로 abstract를 붙이면 됨!
public class Sports { => public abstract class Sports { 수정해 주면 오류 없어짐!

 

Basketball 클래스 (== 자식 클래스)

package com.kh.chap02.abstractAndInterface.part01.basic.model.vo;

// Sports 상속받기
public class Basketball extends Sports{
	
	// 미완성된 클래스인 추상 클래스를 상속받게 되면
	// 부모 클래스에 있는 추상 메소드를 강제로 오버라이딩을 통해 완성시켜 줘야 함
	
	// 필드부
	// 따로 만들 필드 없습니다~
	
	// 생성자부
	public Basketball() {
		
	}
	
	public Basketball(int people) {
		super(people);
	}
	
	// 메소드부
	@Override
	public void rule() {
		System.out.println("손으로 공을 던져 링에 넣어야 함");
	}

}

Football 클래스(== 자식 클래스)

package com.kh.chap02.abstractAndInterface.part01.basic.model.vo;

// Sports 상속받기
public class Football extends Sports {
	
	// 필드부
	// 따로 만들 필드 없습니다~
	
	// 생성자부
	public Football () {
		
	}
	
	public Football(int people) {
		super(people);
	}
	
	// 메소드부
	@Override
	public void rule() {
		System.out.println("손이 아닌 발로 공을 차야 함");
	}

}

BasicRun 클래스

package com.kh.chap02.abstractAndInterface.part01.basic.run;

import com.kh.chap02.abstractAndInterface.part01.basic.model.vo.Basketball;
import com.kh.chap02.abstractAndInterface.part01.basic.model.vo.Football;
import com.kh.chap02.abstractAndInterface.part01.basic.model.vo.Sports;

public class BasicRun {

	public static void main(String[] args) {
		
		/*
		// Sports s = new Sports();
		// 추상 클래스로 만들면 절대 객체 생성 불가
		// => 미완성된 클래스이기 때문
		
		Sports s; // 변수를 선언할 뿐이기 때문에 가능(참조자료형 변수로는 활용 가능)
		
		s = new Football();
		// 아무리 추상클래스 타입이어도 "다형성"에 의해 자식 타입의 객체를 생성 후 담을 수 있음
		*/
		
		// 선언과 동시에 생성하고 싶다면?
		
		Sports s = /* (Sports) */ new Football();
		
		// 객체 배열
		Sports[] arr = new Sports[2];
		arr[0] = new Basketball();
		arr[1] = new Football();
		
		for(int i = 0; i < arr.length; i++) {
			arr[i].rule();
		}

 

 * 추상 클래스(미완성된 클래스) => abstract calss
- 해당 클래스 내부에 추상 메소드가 하나라도 존재하는 순간 반드시 추상 클래스로 정의해야 함
- 단, 추상 메소드가 굳이 없어도 abstract class로 정의하면 추상 클래스로 정의함
  (일반 필드 + 일반 메소드 + 추상 메소드(생략 가능))
  => 개념적 이유: 클래스가 아직 구체적이지 않은 덜 왈성된 상태인 것 같을 때
  => 기술적 이유: 이 클래스를 객체 불가능하게 막고 싶을 때 
- 객체 생성이 불가하나 다형성적을 적용하여 참조변수로는 활용 가능!
 
*추상 메소드(미완성된 메소드) => abstract 반환형
- 미완성된 메소드로 몸통부 { }가 구현되어 있지 않은 메소드
- 자식 클래스에서 오버라이딩을 통해 완성됨 (즉, 강제로 오버라이딩을 해야 함)

 

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() {
		super();
	}

	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 "name: " + name + ", weight: " + weight + ", health: " + health;
	}
	
	// 사람의 행위를 메소드로 표현
		// 일반 메소드 버전
		/*
		public void eat() {
			System.out.println("밥을 먹는다.");
	
		}
		
		public void sleep() {
			System.out.println("잠을 잔다.");
		}
		*/
	
		// 추상 메소드 버전 (abstract, 몸통부 x) => 미완성된 상태 = > 상속받는 측에서 완성시켜 줘야 함(오버라이딩 활용)
		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() {
		super();
	}

	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 super.toString() + ", babyBirth: " + babyBirth;
	}
	
	// 잠을 자는 행위, 밥을 먹는 행위
	@Override
	public void eat() { // 엄마가 밥을 먹으면?
		
		// 몸무게가 기존의 몸무게에 10kg 정도 증가
		// super.weight = super.getWeight() + 10;
		// 직접 접근 안 되니까 getter 메소드를 이용해 접근
		super.setWeight(super.getWeight() + 10);
		// 직접 접근 안 되니까 setter 메소드를 이용해 값 입력
		// 수정할 몸무게 == 기존 몸무게 + 10
		
		// 건강도는 기존의 건강도에 10 감소
		super.setHealth(super.getHealth() - 10);
		// 수정할 건강도 == 기존 건강도 - 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);
	}
	
	// 메소드부
	// 추가 필드 없으므로 getter, setter 필요하지 않음
	
	@Override
	public String toString() {
		return super.toString();
	}
	
	@Override
	public void eat() { // 아기가 밥을 먹으면?
		
		// 몸무게 3 증가
		super.setWeight(super.getWeight() + 3);
		
		// 건강도 1 증가
		super.setHealth(super.getHealth() + 1);
	}
	
	@Override
	public void sleep() { // 아기가 잠을 자면?
		
		// 건강도 3 증가
		super.setHealth(super.getHealth() + 3);
		
	}
	
	

}

FamilyRun 클래스

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 FamilyRun {

	public static void main(String[] args) {
		
		/*
		// 일반 클래스: 객체 생성이 가능
		Person p = new Person();
		
		// 일반 클래스: 다형성 적용 가능
		Person p1 = new Mother();
		Person p2 = new Baby();
		*/
		
		// Person 클래스에 abstract(추상)을 추가하여 추상 클래스로 만들면?
		// 추상 클래스: 객체 생성이 불가능
		// Person p = new Person(); // Cannot instantiate the type Person
		Person p1 = new Mother("김엄마", 50, 70, "출산");
		Person p2 = new Baby("박응애", 3.5, 70);
		
		System.out.println(p1); // 엄마: 몸무게 50, 건강도 70
		System.out.println(p2); // 애기: 몸무게 3.5, 건강도 70
		
		p1.eat(); // 엄마: 몸무게 + 10, 건강도 - 10
		p2.eat(); // 아기: 몸무게 + 3, 건강도 + 1
		p1.sleep(); // 엄마: 건강도 + 10
		p2.sleep(); // 아기: 건강도 + 3
		
		System.out.println("=== 다음날 ===");
		System.out.println(p1);
		System.out.println(p2);
		
		

	}

}


// 출력물
name: 김엄마, weight: 50.0, health: 70, babyBirth: 출산
name: 박응애, weight: 3.5, health: 70
=== 다음날 ===
name: 김엄마, weight: 60.0, health: 70, babyBirth: 출산
name: 박응애, weight: 6.5, health: 74


*인터페이스

모든 필드가 상수 필드이고, 모든 메소드가 추상 메소드인 일종의 추상 클래스
 
[ 표현법 ] 
public interface 인터페이스명 {
 
}
 
 // 필드부: 상수 필드만 정의되어야 함
  
  // 생성자부: 추상 클래스는 어차피 객체 생성이 불가하므로 생성자부 생략 
  
  // 메소드부: 추상 메소드들만 있어야 함
  
 - 인퍼테이스에서 모든 필드는 무조건 상수 필드
 - 인터페이스에서 모든 메소드는 무조건 추상 메소드
 - 무조건 구현해야 될 것들이 있을 때 인터페이스를 만들어서 상속하게 됨
 - 추상 클래스와 다르게 좀 더 강한 규칙성, 강제성을 제공하는 게 인터페이스
  
  *추상 클래스와 인터페이스의 비교

  1. 공통점
  - 객체 생성은 안 되나 다형성은 적용 가능함
  - 상속(구현) 하는 클래스에 추상 메소드를 오버라이딩 하도록 강제함
   
  2. 차이점
  - 추상클래스는 클래스 내에 자유롭게 필드, 메소드를 생성 가능하고
    추상 메소드가 포함되었거나 포함되지 않더라도 abstract class로 생성하면 추상 클래스로 정의됨
    인터페이스는 인터페이스 내에 상수 필드, 추상 메소드로만 구성되어야 함
  - 존재하는 목적이 다름
    추상 클래스: 공통적인 코드를 모아두고 더 가져다가 기능을 "확장"시켜서 쓰겠다 (클래스명 extends 부모클래스명)
    인터페이스: 클래스의 기능 구현을 강제하기 위해서 가져다 쓰겠다 == 적어도 해당 메소드들은 다 가지고 있어야 함
     (클래스명 implements 인터페이스명)
    => 즉, 구현을 강제함으로써 구현 객체들의 같은 동작을 보장할 수 있음
     
 3. extends 와 implements
 - 클래스 간의 상속관계일 경우: 자식클래스명 extends 부모클래스명 (다중상속 불가)
 - 클래스와 인터페이스 간의 구현관계일 경우: 클래스명 implements 인터페이스명, 인터페이스명2, ... (다중구현 가능)
 - 인터페이스와 인터페이스 간의 상속관계일 경우: 자식인터페이스명 extends 부모인터페이스명, 부모인터페이스명2, ... (다중구현 가능)

 

Basic 클래스

package com.kh.chap02.abstractAndInterface.part02.family.model.vo;

// interface: 추상 클래스인데 종특인 애
public interface Basic {
	
	// 필드부: 상수 필드만 선언 가능
	/* public static */ final int NUM = 10;
	// 인터페이스에는 상수 필드만 정의할 수 있기 때문에
	// public static final은 생략 가능함 (묵시적으로 쓰지 않음)
	// private int a; // 일반 필드 선언이 불가
	
	// 메소드부: 추상 메소드만 선언 가능
	/* public static */ void sleep();
	/* public static */ void eat();
	// 인터페이스에는 추상 메소드만 정의할 수 있기 때문에
	// 앞의 public abstract 은 생략 가능함 (묵시적으로 쓰지 않음)

}

Mother, Baby, FamilyRun 클래스

// Mother 클래스
public class Mother extends Person implements Basic {

// Baby 클래스
		// 확장한다 	// 구현한다. 라는 뜻 
public class Baby extends Person implements Basic {

// FamilyRun 클래스
	// 인터페이스 적용 후
		// Basic b = new Basic(); // 객체생성이 불가능
		
		Basic b1 = new Mother("김엄마", 50, 70, "출산");
		Basic b2 = new Baby("박응애", 3.5, 70);
		
		System.out.println(b1);
		System.out.println(b2);
		
		b1.eat(); // 엄마: 몸무게 + 10, 건강도 - 10
		b2.eat(); // 아기: 몸무게 + 3, 건강도 + 1
		b1.sleep(); // 엄마: 건강도 + 10
		b2.sleep(); // 아기: 건강도 + 3
		
		System.out.println("=== 다음날 ===");
		System.out.println(b1);
		System.out.println(b2);
        
 
// 출력물
name: 김엄마, weight: 50.0, health: 70, babyBirth: 출산
name: 박응애, weight: 3.5, health: 70
=== 다음날 ===
name: 김엄마, weight: 60.0, health: 70, babyBirth: 출산
name: 박응애, weight: 6.5, health: 74
저작자표시 (새창열림)
'📗 self-study/📗 KH정보교육원 당산지원' 카테고리의 다른 글
  • [Java] 11_예외처리(Unchecked/Checked Exception)
  • [Java] 10_기본 API(Math, StringPool, StringMethod, StringTokenizer, Wrapper-parsing, Date)
  • [Java] 09_다형성(Polymorphism)
  • [Java] 08_상속(Inheritance, 오버라이딩)
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[Java] 09_다형성(추상 클래스와 인터페이스)
상단으로

티스토리툴바