추상 클래스와 추상 메서드 (23.05.04)

·2023년 5월 4일
0

Java

목록 보기
24/35
post-thumbnail

📝 추상 클래스


💡 추상 클래스(abstract class)

  1. 미완성 메소드(추상 메소드)를 보유하고 있는 클래스
  2. (추상 메소드는 없지만) 객체로 만들면 안 되는 클래스
[접근제한자] abstract class 클래스명 {}

✏️ 추상 클래스의 특징

  1. 미완성 클래스(abstract 키워드 사용)
    자체적으로 객체 생성 불가
    → 반드시 상속하여 객체 생성
  2. abstract 메소드가 포함된 클래스는 반드시 abstract 클래스
    abstract 메소드가 없어도 abstract 클래스 선언 가능
  3. 클래스 내에 일반 변수, 메소드 포함 가능
  4. 객체 생성은 안되지만 참조형 변수 타입으로는 사용 가능

✏️ 추상 클래스의 장점

  • 상속 받은 자식에게 공통된 멤버 제공
  • 일부 기능의 구현을 강제화
    (공통적이나 자식 클래스에 따라 재정의 되어야 하는 기능)


💡 추상 메소드(abstract method)

미완성 메소드

[접근제한자] abstract 반환형 메소드명(자료형 변수명);

✏️ 예시 - 추상 클래스

  • Animal 클래스
package edu.kh.poly.ex2.model.vo;

public abstract class Animal {
	
	// 추상 클래스(abstract class)
    
	// 필드
	private String type; // 종/과 구분
	private String eatType; // 식성(초식, 육식, 잡식)
	
	// 생성자
	// - 추상 클래스는 new 연산자를 이용해서 직접적인 객체 생성은 불가능하지만
	// 	 상속받은 객체 생성 시 부모 부분이 생성될 때 사용된다.
	// 	 == super() 생성자
	public Animal() {
		super(); // 생략 시 컴파일러가 추가
	} // 기본 생성자
	
	public Animal(String type, String eatType) { // 매개변수 생성자 (오버로딩 적용)
		this.type = type;
		this.eatType = eatType;
	}
	
	// 메소드
	// getter / setter
	public String getType() {
		return type;
	}
	
	public void setType(String type) {
		this.type = type;
	}

	public String getEatType() {
		return eatType;
	}

	public void setEatType(String eatType) {
		this.eatType = eatType;
	}
	
	// toString() 오버라이딩
	@Override // 오버라이딩 되었음을 컴파일러에게 알려 주는 어노테이션
	public String toString() {
		return type + " / " + eatType;
	}
	
	// 동물의 공통 기능 추출(추상화)
	// -> 동물은 공통적으로 먹고, 숨쉬지만
	// 	  어떤 동물이냐에 따라 그 방법이 다름!
	//	--> 그럼 어떡할까?
	// 		미완성 상태로 두어 상속받은 자식이 해당 메소드를 정의하도록
	//		오버라이딩을 강제화시킴 --> 추상(abstract) 메소드로 작성
	
	// 먹다
	public abstract void eat();
	
	// 숨쉬다
	public abstract void breath();
	
}
  • Person 클래스
package edu.kh.poly.ex2.model.vo;

public class Person extends Animal{
	// Animal의 추상 메소드를 오버라이딩 하지 않으면 오류 발생
	
	private String name;
	
	// 생성자
	public Person() { // 기본 생성자
		super(); // == Animal의 기본 생성자
	}
	
	public Person(String type, String eatType, String name) { // 매개변수 생성자
		super(type, eatType);
		this.name = name;
	}
	
	// getter / setter
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public void eat() {
		System.out.println("숟가락, 젓가락, 나이프, 포크 등을 이용해서 먹는다.");
	}

	@Override
	public void breath() {
		System.out.println("코와 입으로 숨을 쉰다.");
	}
	
	// toString()
	@Override
	public String toString() {
		return "Person : " + super.toString() + name;
	}
	
	
}
  • Fish 클래스
package edu.kh.poly.ex2.model.vo;

public class Fish extends Animal{
	
	// 생성자
	// -> 생성자 미작성 시 컴파일러가 자동으로 기본 생성자를 추가해 줌
	public Fish() {
		super();
	}
	
	public Fish(String type, String eatType) {
		super(type, eatType);
	}
	
	// 추상 메소드는 상속받으면 오버라이딩이 강제된다.
	@Override
	public void eat() {
		System.out.println("입을 뻐끔 뻐끔 거리면서 먹는다.");
	}

	@Override
	public void breath() {
		System.out.println("아가미 호흡을 한다.");
	}
	
	// toString()
	@Override
	public String toString() {
		return "Fish : " + super.toString();
	}
	
}
  • AbstractService 클래스
package edu.kh.poly.ex2.model.service;

import edu.kh.poly.ex2.model.vo.Animal;
import edu.kh.poly.ex2.model.vo.Fish;
import edu.kh.poly.ex2.model.vo.Person;

public class AbstractService {
	
	public void ex1() {
		
		// 추상 클래스는 객체로 만들 수 있을까? (X)
		// Animal a1 = new Animal();
		
		// Cannot instantiate the type Animal (객체화 할 수 없다)
		
		// 클래스 : 객체의 속성, 기능을 정의한 것 (일종의 설계도)
		// 추상 클래스 : 미완성 메소드를 포함한 클래스 (미완성 설계도)
		// -> 미완성 설계도로는 객체를 만들 수 없다!! -> 오류 발생
		
		// 해결 방법 : Animal을 상속받아 미완성 부분을 구현한 클래스를 이용해 객체 생성
		
		// * 추상 클래스를 상속받은 자식 객체 생성하기
		Person p1 = new Person();
		
		p1.setName("공유");
	
		// 상속 받은 기능 호출
		p1.setType("척추동물");
		p1.setEatType("잡식");
		
		// 오버라이딩한 메소드 호출
		p1.eat();
		p1.breath();
	
		Fish f1 = new Fish();
		
		f1.eat();
		f1.breath();
	
	}

	public void ex2() {
		
		// * 추상 클래스와 다형성 + 바인딩
		
		// - 추상 클래스는 객체로 만들 수 없다.
		// ---> 하지만 "참조 변수"로는 사용할 수 있다.
		
		// ex)	동물 -> 사람? 물고기?
		//		Animal a1 = new Animal(); (X) 
		
		// 		사람 -> 동물				   / 물고기 -> 동물
		// 		Animal a1 = new Person();	 Animal a2 = new Fish();
	
		Animal[] arr = new Animal[2];
		// Animal 참조 변수 배열 선언 및 할당
		
		arr[0] = new Person("사람", "잡식", "김사랑");
		// Animal 부모 = Person 자식 (다형성 중 업캐스팅)
		
		arr[1] = new Fish("물고기", "잡식");
		// Animal 부모 = Fish 자식 (다형성 중 업캐스팅)
		
		// 바인딩 확인
		for(int i=0; i<arr.length; i++) {
			// arr[i] == Animal 참조 변수
			arr[i].eat();
			arr[i].breath();
			System.out.println(arr[i]);
			// void edu.kh.poly.ex2.model.vo.Animal.eat() - 정적 바인딩
			
			// 프로그램 실행 시
			// 참조하고 있는 자식 객체의 오버라이딩 된 eat() 메소드 수행
			// - 동적 바인딩
			// (부모 타입 참조 변수로 메소드를 호출했지만
			// 	자식 타입에 오버라이딩된 메소드가 수행된다)
			
			// 업캐스팅 상태(부모 참조 = 자식 객체)에서
			// 부모 메소드 호출 시, 오버라이딩된 자식 메소드 수행
			
			System.out.println("-----------------------------");
		}
	
	}
	
}
  • 출력 화면 - AbstractService 클래스의 ex1
  • 출력 화면 - AbstractService 클래스의 ex2
profile
풀스택 개발자 기록집 📁

0개의 댓글