TIL - 13.1 추상 [230728]

송원철·2023년 7월 28일

추상 미술의 아버지 ; 바실리 칸딘스키 - 구성 Composition 8

추상 클래스(abstract class)

몸체 없는 메소드를 포함한 클래스 (미완성 설계도)
추상 클래스일 경우 클래스 선언부에 abstract 키워드 사용

[접근제한자] abstract class 클래스명 {}

추상 메소드(abstract method)

몸체 없는 메소드
추상 메소드의 선언부에 abstract 키워드 사용
상속 시 반드시 구현해야 하는, 오버라이딩이 강제화되는 메소드

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

특징

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

장점

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

인터페이스

상수형 필드와 추상 메소드만을 작성할 수 있는 추상 클래스의 변형체
메소드의 통일성을 부여하기 위해 추상 메소드만 따로 모아놓은 것으로
상속 시 인터페이스 내에 정의된 모든 추상메소드 구현해야 함

[접근제한자] interface 인터페이스명 {
	//상수도 멤버로 포함할 수 있음
	public static final 자료형 변수명 = 초기값;

	//추상 메소드만 선언 가능
	[public abstract] 반환자료형 메소드명([자료형 매개변수]);
	//public abstract가 생략되기 때문에
	//오버라이딩 시 반드시 public 표기해야 함
}

특징

  1. 모든 인터페이스의 메소드는 묵시적으로 public abstract
  2. 변수는 묵시적으로 public static final
  3. 객체 생성은 안되나 참조형 변수로는 가능(다형성)

장점

다형성을 이용하여 상위 타입 역할(자식 객체 연결)
인터페이스 구현 객체에 공통된 기능 구현 강제화 (== 구현 객체간의 일관성 제공)
공동 작업을 위한 인터페이스 제공

추상클래스와 인터페이스 비교

정리


Animal

package edu.kh.poly.ex2.model.vo;

public abstract class Animal {
	// 추상 클래스( abstract class)
	// 1. 미완성 메소드(추상 메소드)를 보유하고 있는 클래스
	// 2. 객체로 만들면 안되는 클래스
	// -> 여러 타입들을 관리하기 위한 상위 타입의 목적,
	// 	 객체로 생성하여 사용하기 위한 목적이 아니다
	
	
	//필드
	private String type; // 종/과 구분
	private String eatType; // 식성(초식, 육식, 잡식)
	
	//생성자
	public Animal() {} // 기본 생성자
	
	// - 추상 클래스는 new 연산자를 통해 직접적인 객체 생성은 불가능하지만
	//   상속받은 객체 생성 시 내부 부모 부분이 생성될 때 사용된다.
	
	public Animal(String type, String eatType) { // 매개변수 생성자
		this.type = type;
		this.eatType = eatType;
		
	}

	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;
		
	}
	
	
	// 동물의 공통 기능 추출(추상화)
	// -> 동물은 공통적으로 먹고, 숨쉬고, 움직이지만
	// 어떤 동물이냐에 따라 그 방법이 다름!
	// 	-> 해당 클래스에 메소드를 정의할 수 없다!
	// 	--> 그럼 어떡할까?
	// 	미완성 상태로 두어 상속받은 자식이 해당 메소드를 정의하도록
	// 	오버라이딩을 강제화 시킴-> 추상메소드로 작성
	
	// 먹다
	public abstract void eat();
	
	// 숨쉬다
	public abstract void breath();
	
	// 움직이다
	public abstract void move();
	
}

Person

package edu.kh.poly.ex2.model.vo;

public class Person extends Animal {
	// Animal의 추상 메서드를 오버라이딩 하지 않으면 오류 발생
	
	private String name;
	
	public Person() {}
	
	// 생성자
	public Person(String type, String eatType, String name) {
		super(type, eatType);
		this.name = name;
	}
	
	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("코와 입으로 숨쉰다.");
		
	}

	@Override
	public void move() {
		System.out.println("두발로 걷는다.");
		
	}

	@Override
	public String toString() {
		return "Person : " + super.toString() + " / " + name;
	}
}

Fish

package edu.kh.poly.ex2.model.vo;

public class Fish extends Animal {

	
	public Fish() {}
	
	public Fish(String type, String eatType) {
		super(type, eatType);
		
	}
	
	@Override
	public void eat() {
		System.out.println("입을 뻐끔 뻐끔 거리면서 먹는다.");
	}

	@Override
	public void breath() {
		System.out.println("아가미 호흡을 한다.");
	}

	@Override
	public void move() {
		System.out.println("꼬리로 헤엄치며 움직인다.");
	}
	
	
	@Override
	public String toString() {
		return "Fish : " + super.toString();
	}
	
}

AbstractService

package edu.kh.poly.ex2.model.service;

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

public class AbstractService {
	
	public void ex1() {
		
		//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() {
		// * 추상 클래스와 다형성 + 바인딩
		
		// - 추상클래스는 객체로 만들 수 없다!!!
		// --> 하지만 "참조 변수"로는 사용할 수 있다!
		
		//Animal a1= new Animal(); (X)
		
		// 사람 -> 동물	/	물고기 -> 동물
		//Animal a1 = new Person();  //(O)
		//Animal a2 = new Fish();	 //(O)
		
		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].toString());
			
			// void edu.kh.poly.ex2.model.vo.Animal.eat() - 정적 바인딩
			
			System.out.println("--------------------------");
			
			// 프로그램 실행 시 
			// 참조하고 있는 자식 객체의 오버라이딩된 eat() 메소드 수행
			// - 동적 바인딩
			// --> 부모 타입 참조 변수로 메소드를 호출했지만
			// 	   자식 타입의 오버라이딩된 메소드가 수행된다.
			
		}
		
	}
	
}

AbstractRun

package edu.kh.poly.ex2.run;

import edu.kh.poly.ex2.model.service.AbstractService;
import edu.kh.poly.ex2.model.service.Calculator;
import edu.kh.poly.ex2.model.service.SWCCalculator;

public class AbstractRun {

	public static void main(String[] args) {
		
		AbstractService service = new AbstractService();
		
		Calculator cal = new SWCCalculator();

		System.out.println("합 : " + cal.plus(20, 15));
		System.out.println("차 : " + cal.minus(20, 15));
		System.out.println("곱 : " + cal.multiple(20, 15));
		System.out.println("몫 : " + cal.divide(20, 15));
		
		// 인터페이스 == 미완성 설계도 == 객체생성 불가능
		// -> 추상클래스처럼 참조 변수로는 사용 가능
		
		// 코드의 큰 수정 없이
		// 객체 생성 코드만 바꾸면 새로운 클래스 코드를 수행할 수 있다.
		
		// 인터페이스의 특징
		// 1) 인터페이스를 부모 참조변수로 사용하면
		//    다형성 중 업캐스팅이 적용되서
		//    상속받은 모든 클래스를 자식 객체로 참조할 수 있다.
		
		// -> 이를 이용하여 중요한 메인코드의 수정을 최소화 할 수 있다.
		// ex) Run에 작성된 합, 차, 곱, 몫을 출력하는 코드의 수정 없이
		//     객체 생성 코드 한 줄만 수정하여 다르게 작성된 기능을 수행할 수 있다.
		
		// 2) 자식 클래스에 공통된 메서드 구현을 강제하기 때문에
		// 모든 자식 클래스가 동일한 형태를 띄게 된다.
		// -> 이를 이용하여 공동 작업(팀 프로젝트)에 필요한
		//    개발 환경을 조성할 수 있다. 
		
		
		//service.ex1();
		//service.ex2();
		
	}

}

Calculator

package edu.kh.poly.ex2.model.service;

// 계산기 인터페이스
// -> 모든 계산기에 대한 공통 필드, 기능명을 제공하는 접점의 용도
public interface Calculator {
	
	// 인터페이스 : 추상클래스의 변형체 (추상클래스보다 추상도 높음)
	// - 추상클래스 : 일부만 추상 메서드(0개 이상)
	// - 인터페이스 : 모두 추상메서드
	
	// 필드(묵시적으로 public static final ==> 상수)
	public static final double PI = 3.14;
	static final int MAX_NUM = 100000;
	public int MIN_NUM = -100000;
	int ZERO = 0;
	// 형식이 달라도 모두 public static final이다!
	
	// 메서드 (묵시적으로 public abstract)
	public abstract int plus(int num1, int num2);
	
	public abstract int minus(int num1, int num2);
	
	public abstract int multiple(int num1, int num2);
	
	public abstract int divide(int num1, int num2);
	
}

SWCCalculator

package edu.kh.poly.ex2.model.service;

public class SWCCalculator /*extends Animal */implements Calculator{
	// 클래스, 인터페이스 동시 상속 가능
	// 인터페이스는 다중 상속 가능
	
	// extends : 확장하다, implements : 구현하다
	// (부)클래스 - (자)클래스 : extends
	// (부)인터페이스 - (자)클래스 : implements
	

	@Override
	public int plus(int num1, int num2) {
		return num1 + num2;
	}

	@Override
	public int minus(int num1, int num2) {
		return num1 - num2;
	}

	@Override
	public int multiple(int num1, int num2) {
		return num1 * num2;
	}

	@Override
	public int divide(int num1, int num2) {
		return num1 / num2;
	}
	
}
profile
초보자

0개의 댓글