다형성
사용방법은 동일하지만
다양한 객체를 이용해서
다양한 실행 결과가 나오도록하는 성질
ex) 팥 붕어빵, 슈크림 붕어빵
public class A{
}
public class B extends A{
}
public class Test{
public static void main(String[] args){
B b = new B();
A a = b;
A aa = new B();
}
}
자식 타입은 부모 타입으로 자동 형변환 가능
바로 부모 자식 관계가 아니라
상속 계층에 속하면 자동 타입 변환 가능
class A{}
class B extends A{}
class C extends B{}
class D extends A{}
class E extends D{}
public class test{
public static void main(String[] args){
B b = new B();
C c = new C();
D d = new D();
E e = new E();
A a1 = b;
A a2 = c;
A a3 = d;
A a4 = e;
B b1 = c;
D d1 = e;
//B b3 = e; ERROR
//C c2 = d; ERROR
}
}
부모 타입으로 형변환 된 이후에는
부모 클래스에 선언된 필드와 메소드만 접근 가능
비록 변수는 자식 객체를 참조 하지만
변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정
예외
메소드가 자식 클래스에서 재정의되었다면
자식 클래스의 메소드가 대신호출
public class Parent{
void method1(){
System.out.println("Parent Method1");
}
void method2(){
System.out.println("Parent Method2");
}
}
public class Child extends Parent{
@Override
void method2(){
System.out.println("Child method2");
}
void method3(){
System.out.println("Child method3");
}
}
public class Test{
public static void main(String[] args){
Child child = new Child();
Parent parent = child;
parent.method1();
parent.method2();
//parent.method3(); ERROR
}
}
필드의 다형성 예제
부모 클래스를 상속하는 자식 클래스는 사용법이 동일
자식 클래스는 부모 클래스의 메소드를 재정의 함으로써
더 우수한 결과 출력 가능
자식 타입을 부모 타입으로 변환 가능
Tire
public class Tire{
int maxRotation;//최대 회전수
int accumulatedRotation;//누적 회전수
String location;// 타이어의 위치
Tire(String location, int maxRotation){
this.location = location;
this.maxRotation = maxRotation;
}
boolean roll(){
++accumulatedRotation;
if(accumulatedRotation<maxRotation){
System.out.println(location+"Tire 수명: "+(maxRotation-accumulatedRotation));
return true;
}
else{
System.out.println("*** "+location+" Tire 펑크 ***");
return false;
}
}
}
KumhoTire
public class KumhoTire extends Tire{
KumhoTire(String location, int maxRotation){
super(location, maxRotation);
}
@Override
boolean roll(){
++accumulatedRotation;
if(accumulatedRotation<maxRotation){
System.out.println(location+"KumhoTire 수명: "+(maxRotation-accumulatedRotation));
return true;
}
else{
System.out.println("*** "+location+" KumhoTire 펑크 ***");
return false;
}
}
}
HankookTire
public class HankookTire extends Tire{
HankookTire(String location, int maxRotation){
super(location, maxRotation);
}
@Override
boolean roll(){
++accumulatedRotation;
if(accumulatedRotation<maxRotation){
System.out.println(location+"HankookTire 수명: "+(maxRotation-accumulatedRotation));
return true;
}
else{
System.out.println("*** "+location+" HankookTire 펑크 ***");
return false;
}
}
}
Car
public class Car{
Tire FLtire = new Tire("앞왼쪽",6);
Tire FRtire = new Tire("앞오른쪽",2);
Tire BLtire = new Tire("뒤왼쪽",3);
Tire BRtire = new Tire("뒤오른쪽",4);
int run(){
System.out.println("Car is run");
if(FLtire.roll()==false){stop(); return 1;}
if(FRtire.roll()==false){stop(); return 2;}
if(BLtire.roll()==false){stop(); return 3;}
if(BRtire.roll()==false){stop(); return 4;}
return 0;
}
void stop(){
System.out.println("Car is stop");
}
}
CarTest
public class CarTest{
public static void main(String[] args){
Car car = new Car();
for(int i=0;i<5;i++){
int problemLocation = car.run();
switch(problemLocation){
case 1:
System.out.println("앞왼쪽 HankookTire로 교체");
car.FLtire = new HankookTire("앞왼쪽",15);
break;
case 2:
System.out.println("앞오른쪽 KumhoTire로 교체");
car.FRtire = new KumhoTire("앞오른쪽",13);
break;
case 3:
System.out.println("뒤왼쪽 HankookTire로 교체");
car.BLtire = new KumhoTire("뒤왼쪽",14);
break;
case 4:
System.out.println("뒤오른쪽 KumhoTire로 교체");
car.BRtire = new KumhoTire("뒤오른쪽",11);
break;
}
System.out.println("---------------------------------------------------");
}
}
}
매개변수의 다형성 예제
public class Vehicle{
void run(){
System.out.println("탈 것으로 달립니다.");
}
}
public class Driver{
void drive(Vehicle vehicle){
vehicle.run();
}
}
public class DriverTest{
public static void main(String[] args){
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
}
}
여기서 Driver의 메소드 drive의 매개변수로
Vehicle의 자식 클래스들도 들어올 수 있음
Vehicle의 자식 Bus
public class Bus extends Vehicle{
@Override
void run(){
System.out.println("Bus를 타고 달립니다.");
}
}
Vehicle의 자식 Taxi
public class Taxi extends Vehicle{
@Override
void run(){
System.out.println("Taxi를 타고 달립니다.");
}
}
Bus 객체와 Taxi 객체를 받는 Driver클래스의 메소드 drive
Driver클래스는 이전과 동일
public class DriverTest{
public static void main(String[] args){
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
Bus bus = new Bus();
Taxi taxi = new Taxi();
driver.drive(bus);
driver.drive(taxi);
}
}
강제 타입 변환
부모 타입을 자식 타입으로 변환하는 것
모든 경우 가능한 것이 아님
자식 타입에서 부모 타입으로 변환된 객체만 가능
class A{}
class B extends A{}
class C extends B{}
public class Test{
public static void main(String[] args){
A a = new A();
B b = new B();
C c = new C();
B b1 = c;//부모타입으로 자동 타입 변환
C c1 = (C)b1;//자식타입으로 강제 타입 변환
//C c2 = b1;//ERROR 타입을 명시적으로 해줘야함
//B b2 = a; ERROR
}
}
자동 타입 변환하면 부모에 선언된 필드와 메소드만 사용가능한데
강제 타입 변환한 다음 다시 자식의 필드와 메소드 사용 가능
public class Parent{
String field1;
void method1(){System.out.println("Parent method1");}
void method2(){System.out.println("Parent method2");}
}
public class Child extends Parent{
String field2;
@Override
void method2(){System.out.println("Child method2");}
void method3(){System.out.println("Child method1");}
}
public class Test{
public static void main(String[] args){
Parent parent = new Child();
parent.field1 = "xx";
parent.method1();
parent.method2();
//parent.field2; ERROR
//parent.method3(); ERROR
Child child = (Child)parent;
child.field1 = "asdf";
child.field2 = "xxx";
child.method2();
child.method3();
}
}
실행결과에서 2번째 줄에 있는
Childe method2가 나오는 이유는
method2가 Child 클래스에서 재정의 되었기 때문
객체 타입 확인
부모 변수가 참조하는 객체가
부모객체인지 자식객체인지 확인 하는법
instanceof 연산자 이용
boolean result = 좌항(객체) intanceof 우항(타입)
우항의 타입으로 객체가 생성되었다면 ture 반환
주로 매개값이 어떤 객체인지 확인할 때 쓰임
class Parent{}
class Child extends Parent{}
public class Test{
public static void main(String[] args){
Parent p1 = new Parent();
Child c1 = new Child();
Parent p2 = c1;
instanceOf(p1);
instanceOf(p2);
Child c2 = (Child)p2;
instanceOf(c2);
p2 = p1;
instanceOf(p2);
}
static void instanceOf(Parent p){
if(p instanceof Child){
System.out.println("Child instance");
}
else{
System.out.println("Not Child instance");
}
}
}