- 다형성 (Polymorphism)
- 클래스 형변환
- 객체 배열과 다형성
- 매개 변수와 다형성
- 바인딩
- instanceof 연산자
- 추상클래스
- 인터페이스
다양한 형태를 지니는 성질이라는 뜻으로 하나의 행동으로 여러 가지 일을 수행하는 개념이다.
상속을 이용한 기술이며 부모 클래스 타입 참조변수 하나로 상속 관계에 있는 여러 타입의 자식 객체를 참조할 수 있는 기술이다.
Parent p = new Child();
상속 관계에 있는 부모와 자식 클래스 간에 부모타입의 참조형 변수가
모든 자식 타입 객체의 주소를 참조할 수 있다.
// Sonata 클래스는 Car 클래스의 후손
Car c = new Sonata(); // Sonata 클래스형에서 Car 클래스형으로 바뀜
업 캐스팅은 자식 객체 내부에 있는 부모 객체를 참조 즉 바라보도록 변하는 것으로
자식 객체의 주소를 전달받은 부모 타입의 참조변수를 통해서 접근할 수 있는
객체의 정보는 부모로부터 상속받은 멤버만 참조 가능하다.
자식 객체의 주소를 받은 부모 참조형 변수를 가지고 자식의 멤버를 참조해야 할 경우
부모 클래스 타입의 참조형 변수를 자식 클래스 타입으로 형변환 하는 것이다. 자동으로 처리되지 않기 때문에 반드시 자식 타입을 명시하여 형변환 한다.
// Sonata 클래스는 Car 클래스의 후손
Car c = new Sonata();
((Sonata)c).moveSonata();
클래스 간의 형 변환은 반드시 상속 관계인 클래스끼리만 가능하다.
다형성을 이용하여 상속 관계에 있는 하나의 부모 클래스 타입의 배열 공간에 여러 종류의 자식 클래스 객체를 저장할 수 있다.
// Car 1차원 배열은 Car 참조 변수의 묶음
Car[] carList = new Car[3];
// carList[i]는 Car 참조 변수
carList[0] = new Truck(6, 4, "경유", 1); // 업캐스팅
carList[1] = new LightCar(4, 4, "휘발유", 0.3); // 업캐스팅
carList[2] = new Car(4, 2, "전기");
다형성을 이용하여 메소드 호출 시 부모타입의 변수 하나만 사용해 자식 타입의 객체를 받을 수 있다.
public void execute() {
driveCar(new Sonata());
driveCar(new Avante());
driveCar(new Grandure());
}
public void driveCar(Car c) { }
실제 실행할 메소드 코드와 호출하는 코드를 연결 시키는 것이다.
Car[] carList = new Car[3];
// carList[i] == Car 참조 변수
carList[0] = new Truck(6, 4, "경유", 1); // 업캐스팅
carList[1] = new LightCar(4, 4, "휘발유", 0.3);
carList[2] = new Car(4, 2, "전기");
for (Car c : carList) {
printCar(c);
}
public void printCar(Car c) {
String type = null;
if (c instanceof Truck) type = "[Truck]";
else if (c instanceof LightCar) type ="[LightCar]";
else type = "[Car]";
System.out.println(type + "에 대한 정보입니다.");
System.out.println(c.toString());
}
정적 바인딩 : 프로그램 실행 전 컴파일 단계에서 메서드 호출부와 수행될 메서드를 묶는 것으로 참조 변수의 자료형을 기준으로 연결함
동적 바인딩 : 프로그램 실행 중 실행 당시의 객체의 자료형을 기준으로 메서드 호출부와 수행될 메서드를 묶는 것이며 참조하는 객체의 자료형을 기준으로 연결함
동적 바인딩의 성립 요건
상속 관계로 이루어져 다형성이 적용된 경우 메소드 오버라이딩이 되어 있으면
정적으로 바인딩 된 메소드 코드보다 오버라이딩 된 메소드 코드를 우선적으로 수행한다.
상위 클래스로 형변환된 인스턴스의 원래 자료형을 확인하려고 할 때 사용한다.
즉 현재 참조형 변수가 어떤 클래스 형의 객체 주소를 참조하고 있는지 확인 할 때 사용하며
클래스 타입이 맞으면 true 맞지 않으면 false 반환한다.
if (c instanceof Sonata) { // c 타입이 Sonata 이면
((Sonata)c).moveSonata(); // 다운 캐스팅
} else if (c instanceof Avante) {
((Avante)c).moveAvante();
} else if (c instanceof Grandure) {
((Grandure)c).moveGrandure();
}
몸체 없는 메소드를 포함한 클래스로 미완성 설계도이다.
접근 제한자 abstract class 클래스명 { }
상황에 따라 다르게 구현해야하는 기능만 추상 메소드로 선언한다. 예를 들어 전화와 카메라와 터치 기능 중 터치 기능만 사람에 따라 다르게 구현해내고 싶을 때 사용할 수 있다.
상속 받은 자식에게 공통된 멤버를 제공하며 공통적이나 자식 클래스에 따라 재정의 되어야 하는 일부 기능의 구현을 강제화한다.
몸체 없는 메소드인 추상 메소드는 abstract 키워드를 사용하고 상속 시 반드시 구현해야 하는 오버라이딩이 강제화되는 메소드이다.
접근 제한자 abstract 반환형 메소드명(자료형 변수명);
✍ 인터페이스는 접점이자 사용 설명서라고 생각하자
오로지 상수형 필드와 추상 메소드만을 작성할 수 있는 추상 클래스의 변형체
메소드의 통일성을 부여하기 위해 추상 메소드만 따로 모아놓은 것으로 상속 시 인터페이스 내에 정의된 모든 추상 메소드를 구현해야한다.
// 사용 방법
접근 제한자 interface 인터페이스명 {
// 상수도 멤버로 포함 가능
public static final 자료형 변수명 = 초기값;
// 추상 메소드만 선언 가능
public abstract 반환자료형 메소드명(자료형 매개변수);
}
// 예시
갤럭시S 30
abstract 화면();
abstract 전화();
abstract 터치();
public interface Calculator {
public static final double PI = 3.14;
final int MAX_NUM = 100_000_000;
int MIN_NUM = -100_000_000;
public abstract int plus(int a, int b);
int minus(int a, int b);
int multiple(int a, int b);
double divide(int a, int b);
double areaOfCircle(double r);
int square(int a, int x);
}
public abstract 가 생략되므로 오버라이딩 시 반드시 public 표기해야 한다.
구분 | 추상클래스 | 인터페이스 |
---|---|---|
상속 | 단일 상속 | 다중 상속 |
구현 | extends 사용 | implements 사용 |
추상 메소드 | abstract 메소드 0 개 이상 | 묵시적으로 모든 메소드는 abstract 필드는 public static final |
abstract | 명시적 사용 | 묵시적으로 abstract |
객체 | 객체 생성 불가 | 객체 생성 불가 |
용도 | 참조 타입 | 참조 타입 |