
추상 미술의 아버지 ; 바실리 칸딘스키 - 구성 Composition 8
몸체 없는 메소드를 포함한 클래스 (미완성 설계도)
추상 클래스일 경우 클래스 선언부에 abstract 키워드 사용
[접근제한자] abstract class 클래스명 {}
몸체 없는 메소드
추상 메소드의 선언부에 abstract 키워드 사용
상속 시 반드시 구현해야 하는, 오버라이딩이 강제화되는 메소드
[접근제한자] abstract 반환형 메소드명(자료형 변수명);
상속 받은 자식에게 공통된 멤버 제공.
일부 기능의 구현을 강제화(공통적이나 자식 클래스에 따라 재정의 되어야 하는 기능).
상수형 필드와 추상 메소드만을 작성할 수 있는 추상 클래스의 변형체
메소드의 통일성을 부여하기 위해 추상 메소드만 따로 모아놓은 것으로
상속 시 인터페이스 내에 정의된 모든 추상메소드 구현해야 함
[접근제한자] interface 인터페이스명 {
//상수도 멤버로 포함할 수 있음
public static final 자료형 변수명 = 초기값;
//추상 메소드만 선언 가능
[public abstract] 반환자료형 메소드명([자료형 매개변수]);
//public abstract가 생략되기 때문에
//오버라이딩 시 반드시 public 표기해야 함
}
다형성을 이용하여 상위 타입 역할(자식 객체 연결)
인터페이스 구현 객체에 공통된 기능 구현 강제화 (== 구현 객체간의 일관성 제공)
공동 작업을 위한 인터페이스 제공


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();
}
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;
}
}
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();
}
}
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() 메소드 수행
// - 동적 바인딩
// --> 부모 타입 참조 변수로 메소드를 호출했지만
// 자식 타입의 오버라이딩된 메소드가 수행된다.
}
}
}
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();
}
}
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);
}
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;
}
}