다형성 (Polymorphism)

Agnes Park·2022년 3월 5일
0

JAVA

목록 보기
23/34

1. 다형성 ( Polymorphism )

하나의 이름의 클래스나 메소드가 '여러 가지 형태의 동작을 하는 능력'

  • 클래스의 다형성:
    한 타입의 참조변수로 여러타입의 객체를 참조 가능.
    조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조가능한것
  • 메소드의 다형성:
    메소드 오버로딩, 메소드 오버라이딩
package com.lec.java.oop01;

public class Polymorphism01Main {

	public static void main(String[] args) {
		System.out.println("다형성(Polymorphism)");
		
		System.out.println();
		
		// v1, c1, h1의 타입이 다르다
		// 각각의 타입에 맞는 인스턴스 생성한 뒤 대입
		Vehicle v1 = new Vehicle();
		Car c1 = new Car();
		HybridCar h1 = new HybridCar();
		
		// 각각의 타입에 오버라이딩 된 메소드가 동작함
		v1.displayInfo();
		c1.displayInfo();
		h1.displayInfo();
		
		System.out.println();
		
		// car1, car2는 동일한 Vehicle 타입변수 (각각 Car, HybridCar 객체를 담음)
		Vehicle car1 = new Car();	// 조상 <- 자손 (가능)
		Vehicle car2 = new HybridCar();
		Car car3 = new HybridCar();
		
//		HybridCar car7 = new Vehicle();	// 자손 <- 조상 (불가) ERROR : cannot convert from Vehicle to HybridCar
		
		Object car8 = new Vehicle();
		
		// car1 ~ car3 변수 타입에 관계없이
		// 오버라디디디된 메소드가 '알아서' 동작한다.
		car1.displayInfo();	// Car
		car2.displayInfo();	// HybridCar()
		car3.displayInfo();	// HybridCar()
		
		System.out.println("\n 프로그램 종료");
	} // end main()
	
	// TODO

} // end class
package com.lec.java.oop01;

public class Vehicle {

	private int speed;

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}
	
	public void displayInfo() {
		System.out.println("--- Vehicle 정보 ---");
		System.out.println("speed: " + speed);
	}	
}
package com.lec.java.oop01;

public class Car extends Vehicle {

	private int oil;

	public int getOil() {
		return oil;
	}

	public void setOil(int oil) {
		this.oil = oil;
	}
	
	@Override
	public void displayInfo() {
		System.out.println("--- Car 정보 ---");
		System.out.println("speed: " + getSpeed());
		System.out.println("oil: " + oil);
	}

}
package com.lec.java.oop01;

public class HybridCar extends Car {

	private int electricity;

	public int getElectricity() {
		return electricity;
	}

	public void setElectricity(int electricity) {
		this.electricity = electricity;
	}
	
	@Override
	public void displayInfo() {
		System.out.println("--- HybridCar 정보 ---");
		System.out.println("speed: " + getSpeed());
		System.out.println("oil: " + getOil());
		System.out.println("electricity:" + electricity);
	}
}

2. 다형성의 유용성

  • 다형성에 의해서, 자식타입 객체가 부모타입으로 자동 형변환 가능!
  • 부모(조상)타입 만으로도 상속된 모~든 자손 타입들을 담을 수 있다.
public class Polymorphism02Main {

	public static void main(String[] args) {
		System.out.println("다형성의 사용 (유용성)");

		// 다형성에 의해서, 자식타입 객체가 부모타입으로 자동 형변환 가능!
		Vehicle car1 = new Vehicle();
		Vehicle car2 = new Car();
		Vehicle car3 = new HybridCar();
		
		// 다형성의 유용성 1
		// 부모타입으로 모든 자손 타입들을 담을 수 있다.
		Vehicle [] car = new Vehicle[3];
		car[0] = new Vehicle();
		car[1] = new Car();
		car[2] = new HybridCar();
		
		for (int i = 0; i < car.length; i++) {
			car[i].displayInfo();	// 조상타입 한가지로 한꺼번에 동작 가능
		}
		
		// 다형성이 없었다면?  각 타입별로 변수들을 만들고 따로따로 사용해야 하는 왕불편.
	    //      Vehicle car1 = new Vehicle();
	    //      Car car2 = new Car();
	    //      HybridCar car3 = new HybridCar();
	    //      car1.displayInfo();      
	    //      car2.displayInfo();
	    //      car3.displayInfo();
		
		// 다형성의 유용성 2
		// 다형성의 유용함은 매개변수, 혹은 리턴 타입에도 적용된다
		// println의 매개변수 Object의 참조변수가 넘겨지면,
		// 내부적으로 해당 클래스의 toString() 메소드가 불리게 됨
		System.out.println(car1);	// print(Vehicle) ??? (x) -> BUT, println -> object 타입은 매개변수로 받을 수 있음
		System.out.println(car2);
		System.out.println(car3);
		
		System.out.println();
		
		// instanceof 연산자
	    // 용법: 변수/값 instanceof 클래스 
	    // 결과: true / false
		System.out.println(car1 instanceof Vehicle); // instance 우: 클래스명 / 좌: 변수나 값
		System.out.println(car1 instanceof Car);
		System.out.println(car2 instanceof Vehicle);
		System.out.println(car2 instanceof HybridCar);
		
		System.out.println();
		Vehicle car4 = new Vehicle();
		Car car5= new Car();
		HybridCar car6 = new HybridCar();
		
		driveCar(car4);
		driveCar(car5);
		driveCar(car6);
		
		System.out.println("\n 프로그램 종료");
	} // end main()

	public static void driveCar(Vehicle v) {
		v.setSpeed(100);
		v.displayInfo();
	}

} // end class

/* 코드만 보아도 알아요~
 * A a = new B()   ←  A 는 B 의 조상타입
 * R doSomethig(K p1){..}  ← K 는 Z 의 조상타입
 * Y y = doSomething(new Z()) ← Y 는 R 의 조상타입
 * 
 */
package com.lec.java.oop01;

public class Vehicle {

	private int speed;

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}
	
	public void displayInfo() {
		System.out.println("--- Vehicle 정보 ---");
		System.out.println("speed: " + speed);
	}
	
	
}
package com.lec.java.oop01;

public class Car extends Vehicle {

	private int oil;

	public int getOil() {
		return oil;
	}

	public void setOil(int oil) {
		this.oil = oil;
	}
	
	@Override
	public void displayInfo() {
		System.out.println("--- Car 정보 ---");
		System.out.println("speed: " + getSpeed());
		System.out.println("oil: " + oil);
	}

}
package com.lec.java.oop01;

public class HybridCar extends Car {

	private int electricity;

	public int getElectricity() {
		return electricity;
	}

	public void setElectricity(int electricity) {
		this.electricity = electricity;
	}
	
	@Override
	public void displayInfo() {
		System.out.println("--- HybridCar 정보 ---");
		System.out.println("speed: " + getSpeed());
		System.out.println("oil: " + getOil());
		System.out.println("electricity:" + electricity);
	}

}

3. 다형성의 형변환

package com.lec.java.oop03;

public class Polymorphism03Main {

	public static void main(String[] args) {
		System.out.println("다형성의 어려움");
		
		Vehicle car1 = new Vehicle();
		Vehicle car2 = new Car();
		Vehicle car3 = new HybridCar();
		
		car2.setSpeed(10);
		// car2는 Vehicle 타입으로 선언되어 있으므로,
		// Vehicle 클래스에 정의된 메소드를 사용할 수 있다.
		
		// 반면..
//		car2.setOil(100);	// 에러 : undefined for the type Vehicle
		// car2는 Vehicle 타입으로 선언되어 있으므로,
		// Vehicle이 아닌 다른 클래스(심지어 자식 클래스이더라도)에 정의된
		// 메소드는 사용할 수 없다.
		// 따라서, 실제로 Car 타입 인스턴스로 생성되긴 했지만,
		// Vehicle 타입 참조변수는 Car 클래스에 있는 메소드를 사용할 수 없다.
		
		car2.displayInfo();
		// car2는 Vehicle 타입으로 선언되었으므로,
	    // displayInfo()는 Vehicle 클래스에서 정의된 메소드를 찾아가지만,
	    // 인스턴스가 생성될 때 Car 타입으로 생성되어서,
	    // Car 클래스에서 override된 displayInfo() 메소드가
	    // 부모 클래스의 displayInfo()를 덮어써 버리게 됨
	    // 결과는 Car의 정보를 출력하게 됨
		
		((Car)car2).setOil(50);
		// 실제로 Car 클래스의 인스턴스로 생성된 car2 변수는
		// 형변환(casting)을 통해서 Car 타입으로 변환할 수 있고,
		// Car 클래스에 정의된 메소드를 사용할 수 있다.
		
		car2.displayInfo();
		
		
		((Car)car1).setOil(10);	// 오류 : ClassCastException - 클래스 형변환중에 발생된 오류 (Vehicle cannot be cast to class com.lec.java.oop03.Car)
		// ClassCastException 발생:
	    // 실제로 Vehicle 클래스의 인스턴스로 생성된 car1을 
	    // 자식 클래스인 Car로 강제 형변환을 하게 되면 문제가 발생할 수 있다.
	    // 예외는 setOil() 을 호출하는 과정이 아니라, 형변환 하는 과정에서 발생된다
		
		
		System.out.println("\n 프로그램 종료");
	} // end main()

} // end class

0개의 댓글