1. 다형성 polymorphism
🚀 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질을 말함
🚀 객체는 부품과 같아서 프로그램을 구성하는 객체를 바꾸면 프로그램의 실행 성능이 다르게 나올 수 있다.
- 객체 사용 방법이 동일하다는 것은 동일한 메소드를 가지고 있다는 뜻
- 한국 타이어와 금호 타이어는 모두 타이어를 상속하고 있으므로 부모의 메소드를 동일하게 가지고 있다고 말할 수 있다.
- 타이어 메소드 호출 시 오버라이딩 된 메소드가 호출되는데, 오버라이딩 된 내용은 두 타이어가 다르기 때문에 실행 결과가 다르게 나옴
- 이것을 '다형성' 이라고 하는데 다형성을 구현하기 위해서는 자동 타입 변환과 메소드 재정의가 필요하다.
1) 필드 다형성
👾 필드 타입은 동일하지만(사용 방법은 동일하지만) 대입되는 객체가 달라져서 실행 결과가 다양하게 나올 수 있는 것을 말한다.
public class Car {
//필드 선언
public Tire tire;
//메소드 선언
public void run() {
//tire 필드에 대입된 객체의 roll() 메소드 호출
tire.roll();
}
}
public class Tire {
//메소드 선언
public void roll() {
System.out.println("회전합니다.");
}
}
public class HankookTire extends Tire {
//메소드 재정의(오버라이딩)
@Override
public void roll() {
System.out.println("한국 타이어가 회전합니다.");
}
}
public class KumhoTire extends Tire {
//메소드 재정의(오버라이딩)
@Override
public void roll() {
System.out.println("금호 타이어가 회전합니다.");
}
}
public class CarExample {
public static void main(String[] args) {
//Car 객체 생성
Car myCar = new Car();
//Tire 객체 장착
myCar.tire = new Tire();
myCar.run();
//HankookTire 객체 장착
myCar.tire = new HankookTire();
myCar.run();
//KumhoTire 객체 장착
myCar.tire = new KumhoTire();
myCar.run();
}
}
- Car 클래스의 run() 메소드는 tire 필드에 대입된 객체의 roll() 메소드를 호출한다.
- 어떤 타이어를 장착했는지에 따라 roll() 메소드의 실행 결과는 달라지게 된다. 이것이 바로 '필드의 다형성'이라고 함
2) 매개변수 다형성
👾 다형성은 필드보다는 메소드를 호출할 때 많이 발생함
👾 메소드가 클래스 타입의 매개변수를 가지고 있을 경우, 호출할 때 동일한 타입의 객체를 제공하는 것이 정석이지만 자식 객체를 제공할 수도 있다.
public class Driver {
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
- drive() 메소드는 매개값으로 전달받은 vehicle의 run() 메소드를 호출함
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
- 일반적으로 drive() 메소드를 호출한다면 위와 같이 Vehicle의 객체를 제공
- but, 자동 타입 변환으로 인해 매개값으로 Vehicle의 자식 객체도 제공할 수 있음!
⚡️ drive() 메소드는 매개변수 vehicle이 참조하는 객체의 run() 메소드를 호출하는데, 자식 객체가 run() 메소드를 재정의하고 있다면 재정의된 run() 메소드가 호출된다.
☑️ 어떤 자식 객체가 제공하느냐에 따라 drive() 실행 결과는 달라진다. 이것이 '매개변수의 다형성'
public class Vehicle {
//메소드 선언
public void run() {
System.out.println("차량이 달립니다.");
}
}
public class Bus extends Vehicle {
//메소드 재정의(오버라이딩)
@Override
public void run() {
System.out.println("버스가 달립니다.");
}
}
public class Taxi extends Vehicle {
//메소드 재정의(오버라이딩)
@Override
public void run() {
System.out.println("택시가 달립니다.");
}
}
public class Driver {
//메소드 선언(클래스 타입의 매개변수를 가지고 있음)
public void drive(Vehicle vehicle) {
vehicle.run();
}
}
public class DriverExample {
public static void main(String[] args) {
//Driver 객체 생성
Driver driver = new Driver();
//매개값으로 Bus 객체를 제공하고 driver() 메소드 호출
Bus bus = new Bus();
driver.drive(bus);
//매개값으로 Taxi 객체를 제공하고 driver() 메소드 호출
Taxi taxi = new Taxi();
driver.drive(taxi);
}
}
응용 예제
public class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스 점수
Product(int price){
this.price = price;
this.bonusPoint = (int)(price / 10.0); // 보너스점수는 제품가격의 10%
}
}
public class Tv extends Product{
Tv () {
// 부모클래스의 생성자 Product(int price)를 호출한다.
super(100); // Tv의 가격을 100만원으로 한다.
}
@Override
public String toString() {
return "Tv";
}
}
public class Audio extends Product{
Audio() {
super(50);
}
@Override
public String toString() {
return "Audio";
}
}
public class Computer extends Product{
Computer () {
super(200);
}
@Override
public String toString() {
return "Computer";
}
}
1. Object 클래스 상속:
- 모든 Java 클래스는 자동으로 Object 클래스를 상속받는다. Object 클래스는 모든 클래스의 최상위 부모 클래스이고, 이 클래스에서 제공하는 여러 메서드들이 모든 클래스에서 사용할 수 있게 된다. 그 중 하나가 toString() 메서드
2. toString() 메서드:
- Object 클래스에는 이미 toString() 메서드가 정의되어 있기 때문에, 어떤 클래스든 toString() 메서드를 오버라이딩할 수 있다. 따라서, Product 클래스에 따로 toString() 메서드를 정의하지 않더라도, Tv 클래스에서 이 메서드를 오버라이딩하는 것이 가능
public class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스점수
/* Product[] products = new Product[10]; // 구입한 제품을 저장하기 위한 배열
int i = 0; // Product 배열에 사용될 카운터 */
ArrayList<Product> products = new ArrayList<>();
void buy (Product product){ // 부모클래스 타입으로 매개변수 받음.
// 부모 클래스의 필드 사용. price, bonusPoint
if (money < product.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}
money -= product.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
bonusPoint += product.bonusPoint; // 제품의 보너스 점수를 추가한다.
products.add(product); // 구입한 제품을 ArrayList에 저장한다.
System.out.println(product + " 을/를 구입하셨습니다.");
}
void summary () { // 구매한 물품에 대한 정보를 요약해서 보여 준다.
int sum = 0; // 구입한 물품의 가격합계
String itemList = ""; // 구입한 물품목록
if(products.isEmpty()) { // ArrayList가 비어있는지 확인한다.
System.out.println("구입하신 제품이 없습니다.");
return;
}
// ArrayList의 i번째에 있는 객체를 얻어 온다.
for(int i =0; i < products.size(); i++) {
Product product = products.get(i);
sum += product.price;
itemList += (i==0) ? "" + product : ", " + product;
}
/* // 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
// 1) for 이용
for (int i = 0; i < products.length; i++) {
if (products[i] == null)
break;
sum += products[i].price;
itemList += products[i] + ", ";
}
// 2) foreach 사용
// for(각 요소의 타입과 요소를 담을 변수 : 배열 또는 컬렉션)
for (Product product : products) {
if (product == null)
break;
sum += product.price;
itemList += product + ", ";
}
// 3) 반복을 줄이기 위해 인스턴스 변수 사용
for (int i = 0; i < this.i; i++) {
sum += products[i].price;
itemList += products[i] + ", ";
} */
System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
void refund(Product product) { // 구입한 제품을 환불한다.
if (products.remove(product)) { // 제품을 ArrayList에서 제거한다.
money += product.price;
bonusPoint -= product.bonusPoint;
System.out.println(product + "을/를 반품하셨습니다.");
} else { // 제거에 실패한 경우
System.out.println("구입하신 제품 중 해당 제품이 없습니다.");
}
}
}
public class Test {
/*
코딩 순서 : Product -> Tv -> Computer -> Buyer -> Test
*/
public static void main(String[] args) {
Buyer b = new Buyer();
Tv tv = new Tv();
Computer com = new Computer();
Audio audio = new Audio();
b.buy(tv); // Tv 을/를 구입하셨습니다.
b.buy(com); // Computer 을/를 구입하셨습니다.
b.buy(audio); // Audio 을/를 구입하셨습니다.
b.summary(); // 구입하신 물품의 총금액은 350만원입니다. 구입하신 제품은 Tv, Computer, Audio입니다.
System.out.println();
b.refund(com); // Computer을/를 반품하셨습니다.
b.summary(); // 구입하신 물품의 총금액은 150만원입니다. 구입하신 제품은 Tv, Audio입니다.
}
}
* 내용 참고 - 책 '이것이 자바다' 및 학원 강의 자료
'Programming Language > JAVA' 카테고리의 다른 글
[Java] 객체 타입 확인 (0) | 2024.08.26 |
---|---|
[Java] 타입 변환 (0) | 2024.08.24 |
[Java] final 클래스와 final 메소드 · protected 접근 제한자 (0) | 2024.08.23 |
[Java] 오버라이딩 Overriding (0) | 2024.08.11 |
[Java] 상속 Inheritance (0) | 2024.08.11 |