동일한 타입을 사용하지만 실행 결과가 다양한 결과(객체)가 나오며 이용할 수 있는 성질
서로 다른 객체들이 연결되고 자신의 역할을 수행할 때, 다른 객체로 교체될 수 있어야 한다.
이를 위해 다형성이 필요하다.
다형성을 프로그램상에서 구현하기 위해서는 상속, 오버라이딩, 타입 변환을 이용한다.
: 프로그램 실행 도중 컴파일러에 의해 자동으로 타입 변환이 일어나는 것
부모클래스 변수 = 자식 클래스 타입;
public class Animal {
boolean isMale;
public void makeSound(){
System.out.println("kkkkk");
}
}
public class Cat extends Animal {
String name;
public Cat(String name){
super();
this.name = name;
}
@Override
public void makeSound(){
System.out.println("meowww");
}
public String getName(){
return this.name;
}
}
public class Example{
public static void main(String[] args){
Animal animal = new Cat("kitty");
animal.makeSound(); // meowww
animal.getName(); // COMPILE ERROR!
}
}
코드 설명
Heap 영역에는 Animal 클래스의 특성을 상속받은 Cat 객체가 생성된다.
해당 객체는 Animal 타입으로 참조되는 클래스 타입이다.
Animal 타입은 animal 변수가 참조할 수 있는 객체의 종류로, 메소드 영역에 존재하는 Animal 클래스의 구조와 메소드를 참조할 수 있게 된다.
animal 변수로 메소드를 호출할 때는 Cat 객체의 Overriding 된 메소드를 호출한다.
Cat 객체가 Animal 클래스로 업캐스팅 되었을 때, Cat 클래스에만 있던 인스턴스 멤버는 참조 변수를 통해 직접 참조할 수 없다.
Animal 타입의 참조 변수로는 Cat 클래스에 정의된 getName() 메소드에 접근할 수 없기 때문에 컴파일 에러가 발생한다.
Cat 타입으로 명시적으로 캐스팅한 후에 getName() 메소드를 호출해야 한다.
: 필드의 타입에는 변화가 없지만, 실행 도중 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라질 수 있다.
public class Bicycle {
Tire frontTire = new Tire("앞바퀴", 7);
Tire backTire = new Tire("뒷바퀴", 5);
int run(){
System.out.println("자전거 출발!");
if (!frontTire.roll()){ stop(); return 1; }
if (!backTire.roll()){ stop(); return 2; }
return 0;
}
void stop(){ System.out.println("자전거 멈춤!"); }
}
public class Tire {
public String location;
public int maxRotation;
public int accumulatedRotation;
public Tire(String location, int maxRotation){
this.location = location;
this.maxRotation = maxRotation;
}
public boolean roll(){
accumulatedRotation++;
if(accumulatedRotation < maxRotation){
System.out.println(location + "타이어 수명 : "
+ (maxRotation-accumulatedRotation));
return true;
}else{
System.out.println(location + "타이어 펑크");
return false;
}
}
}
class HankookTire extends Tire {
public HankookTire(String location, int maxRotation){
super(location, maxRotation);
}
}
class KumhoTire extends Tire {
public KumhoTire(String location, int maxRotation){
super(location, maxRotation);
}
}
public class Example {
public static void main(String[] args){
Bicycle bicycle = new Bicycle();
int tireLocation = 0;
for(int i=1; i<=3; i++){
tireLocation = bicycle.run();
if (tireLocation == 0) break; // 타이어 문제 없으면 반복 종료
switch(tireLocation){
case 1:
System.out.println("앞바퀴 교체!");
bicycle.frontTire = new HankookTire("앞바퀴", 14);
break;
case 2:
System.out.println("뒤바퀴 교체!");
bicycle.backTire = new KumhoTire("뒤바퀴", 10);
break;
}
}
}
}
public class Bicycle {
Tire[] tires = {
Tire frontTire = new Tire("앞바퀴", 7);
Tire backTire = new Tire("뒷바퀴", 5);
}
int run(){
System.out.println("자전거 출발!");
for(int i; i<tires.length; i++){
if(tires[i].roll()==false){
stop();
return (i+1);
}
}
return 0;
}
void stop(){ System.out.println("자전거 멈춤!"); }
}
public class Example {
public static void main(String[] args){
Bicycle bicycle = new Bicycle();
for(int i=1; i<=5; i++){
int problemTire = bicycle.run();
if(problemTire != 0){
System.out.println(bicycle.tires[problemTire-1].location+ "교체");
bicycle.tires[problemTire-1]
= new HankookTire(bicycle.tires[problemTire-1].location, 15);
}
}
}
}
자식클래스 변수 = (자식클래스) 부모클래스 타입
public class Bicycle{
void start(Tire tire){
tire.roll();
}
}
public class AbcTire extends Tire {
public int price;
@Override
public void roll(){
System.out.println("AbcTire 데굴");
}
}
public class Example{
public static void main(String[] args){
// 필드 자동 타입변환
Tire tire = new AbcTire();
tire.roll(); // AbcTire 데굴
// 강제 타입 변환
AbcTire abcTire = (AbcTire) tire;
abcTire.price = 100000;
// 메소드 자동 타입변환
Bicycle bicycle = new Bicycle();
AbcTire abc = new AbcTire();
bicycle.start(abc); // Tire -> AbcTire 자동 타입 변환!
}
}
Parent parent = new Child();
Child child = (Child)parent;
parent
(부모 객체 타입 변수)가 자식 객체를 참조하고 있기 때문에,parent
는 자식 객체 타입으로 다운 캐스팅이 가능하다.Parent parent = new Parent();
Child child = (Child) parent;
parent
(부모 객체 타입 변수)는 부모 객체만를 참조하고 있기 때문에,ClassCastException
이 발생한다.parent
을 다운 캐스팅할 수 없다.
instanceof
연산자
- 부모 변수가 참조하는 객체가
Parent
인지Child
인지 확인하는 방법boolean res = 객채 instanceof 타입
if(parent instanceof Child){
Child child = (Child)parent;
System.out.println("강제 타입 변환");
}
실체간의 공통되는 필드와 메소드를 추출해 선언한 클래스
객체를 직접 생성해서 사용할 수 없고, 상속을 통해 자식 클래스만 생성 가능하다.
public abstract class Car{
public String brand;
public Car(String brand){
this.brand = brand;
}
public abstract void start();
public void driving(){
System.out.println("운전중...");
}
}
public class ElectronicCar extends Car{
public ElectronicCar(String brand){
super(brand);
}
@Override
public void start(){
System.out.println("시동 버튼 누르기");
}
public void charging(){
System.out.println("충전중...");
}
}
public class Example{
public static void main(String[] args){
ElectronicCar elCar = new ElectronicCar("테슬라");
carStart(elCar); // 자동 타입 변환
elCar.driving(); // 운전중...
elCar.charging(); // 충전중...
}
public void carStart(Car car){
car.start(); // 시동 버튼 누르기
}
}