매개변수의 다형성
o 참조변수의 다형성 특징은 매개변수에도 적용이 된다. 어떤 메소드에서 매개변수를 특정 타입 (조상)클래스의 자손 클래스 타입으로 참조변수를 받는 경우 자손 클래스가 여러 개면 해당 자손 클래스 들을 사용하기 위해 메소드도 추가해야 한다.
o 그러나 매개변수를 자손 클래스 타입 참조 변수 대신 조상 클래스 참조 변수로 사용한다면 조상 클래스 참조변수를 받는 메소드 하나로 여러 자손 클래스 타입의 값을 입력 받을 수 있다.
package JavaProject;
public class Test {
public static void main(String[] args) {
Buyer b = new Buyer();
Tv t = new Tv();
b.buy(t); //b.buy(new Tv());로도 가능하다.
b.buy(new Computer());
b.buy(new Audio());
System.out.println("현재 남은 돈은 " + b.money + "만원 입니다.");
System.out.println("현재 보너스 점수는 " + b.bonusPoint + "점 입니다.");
}
}
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price){
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product {
Tv() {super(300);}
public String toString() {return "Tv";}
}
class Computer extends Product {
Computer() {super(200);}
public String toString() {return "Computer";}
}
class Audio extends Product {
Audio() {super(100);}
public String toString() {return "Audio";}
}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스 점수
/*
void buy (Tv t) {
// Buyer가 가진 돈에서 제품의 가격을 뺀다
money = money - t.price;
// Buyer의 보너스점수에 제품의 보너스 점수를 더한다.
bonusPoint += t.bonusPoint;
}
void buy (Computer c) {
money = money - c.price;
bonusPoint += c.bonusPoint;
}
void buy (Audio a) {
money = money - a.price;
bonusPoint += a.bonusPoint;
}
*/// 위 메소드 대신 조상 타입의 클래스를 매개변수로 하여 아래의 메소드 하나로 가능하다.
void buy(Product p) {
money = money - p.price;
bonusPoint += p.bonusPoint;
System.out.println(p+"을/를 구입하셨습니다.");
}
}
|
- 매개변수가 Product타입의 참조변수라는 것은, 메서드의 매개변수로 Product클래스의 자손타입의 참조변수면 어느 것이나 매개변수로 받아들일 수 있다는 뜻이다.
- 참조변수 p로 인스턴스의 price와 bonusPoint를 사용할 수 있기에 이와 같이 할 수 있다.
- 다른 제품 클래스를 추가할 때 Product클래스를 상속받기만 하면 buy(Product)메서드의 매개변수로 받아들여질 수 있다.
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price){
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Audio extends Product {
int cash=50; //현금가
Audio() {super(100);}
public String toString() {return "Audio";}
}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int cash = 2000; // 현금 소유 금액
int bonusPoint = 0; // 보너스 점수
void buy (Audio a) {
cash = cash - a.cash; // 현금 가격
money = money - a.price;
bonusPoint += a.bonusPoint;
}
void buy(Product p) {
money = money - p.price;
bonusPoint += p.bonusPoint;
// cash = cash - p.cash; // 에러, Product클래스에는 cash멤버변수가 없다.
System.out.println(p+"을/를 구입하셨습니다.");
}
}
|
- 매개변수로 조상 클래스(Product)타입을 받을 경우 자손 클래스(Audio)에만 선언된 멤버 변수는 사용할 수 없다.
- 각각의 자손별로 정의된 멤버 변수를 사용이 불가능하고 공통된 멤버 변수인 부모 클래스의 멤버 변수만 사용할 수 있다.
o 매개변수 다형성의 예로 PrintStream에 정의되어 있는 print(Object o)메서드를 살펴보면 print(Object o)는 매개변수로 Object타입의 변수가 선언되어 있다. Object클래스는 모든 클래스의 조상이므로 이 메서드의 매개변수로 어떤 타입이든 가능하기에 모든 타입의 인스턴스를 처리할 수 있다.
public void print(String s) {
write(String.valueOf(s)); // valueof()가 반환한 문자열을 출력한다.
}
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString(); // 문자열을 반환한다.
}
|
여러 종류의 객체를 배열로 다루기 – 객체 배열
o 조상타입의 참조변수로 객체를 참조하는 것이 가능하므로 참조변수 배열을 사용하여 공통의 조상을 가진 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다.
o 또는 묶어서 다루고 싶은 객체들의 상속관계를 따져서 가장 가까운 공통조상 클래스 타입의 참조변수 배열을 생성해서 객체들을 저장할 수 있다.
|
|
package JavaProject;
public class Test {
public static void main(String[] args) {
Buyer b = new Buyer();
b.buy(new Tv());
b.buy(new Computer());
b.buy(new Audio());
b.summary();
}
}
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price){
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product {
Tv() {super(100);}
public String toString() {return "Tv";}
}
class Computer extends Product {
Computer() {super(200);}
public String toString() {return "Computer";}
}
class Audio extends Product {
Audio() {super(50);}
public String toString() {return "Audio";}
}
class Buyer {
int money = 1000;
int bonusPoint = 0;
Product[] item = new Product[10]; // 구입한 제품을 저장하기 위한 배열
int i = 0; // Product배열 item에 사용될 카운터
void buy(Product p) {
if(money<p.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}
money -= p.price; // 가진 돈에서 제품가격을 뺀다.
bonusPoint += p.bonusPoint; // 제품의 보너스포인트를 더한다.
item[i++] = p; // 제품을 Product[] item에 저장한다.
System.out.println(p+"을/를 구입하셨습니다.");
}
void summary() { // 구매한 물품의 정보를 요약해서 보여준다.
int sum = 0; // 구입한 물품의 가격합계
String itemList =""; // 구입한 물품목록
//반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
for(int i=0; i<item.length;i++) {
if(item[i]==null) break;
sum += item[i].price;
// itemList += item[i] + ", ";
itemList += (i==0)? item[i] : ", "+item[i];
}
System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
}
|
- Buyer클래스에 Product배열을 및 item[i++]=p 문장을 추가하여 물건을 구입 시 배열에 저장되도록 했다.
- 모든 제품클래스의 조상인 Product클래스 타입의 배열을 사용함으로써 구입한 제품을 하나의 배열로 간단하게 다룰 수 있다.
o 위 예제는 배열의 크기가 10이기에 제품의 11개 이상 구입할 수 없는 문제가 있다. 이럴 경우 Vector 클래스를 이용하면 되는데 Vector클래스는 내부적으로 Object타입의 배열을 가지고 있어서, 이 배열에 객체를 추가하거나 제거할 수 있게 되어있다. Vector는 단지 동적으로 크기가 관리되는 객체배열이라고 보면 된다.
package JavaProject;
import java.util.Vector;
public class 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);
b.buy(com);
b.buy(audio);
b.summary();
System.out.println();
b.refund(tv);
b.summary();
}
}
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price){
this.price = price;
bonusPoint = (int)(price/10.0);
}
}
class Tv extends Product {
Tv() {super(100);}
public String toString() {return "Tv";}
}
class Computer extends Product {
Computer() {super(200);}
public String toString() {return "Computer";}
}
class Audio extends Product {
Audio() {super(50);}
public String toString() {return "Audio";}
}
class Buyer {
int money = 1000;
int bonusPoint = 0;
Vector item = new Vector(); // 구입한 제품을 저장하는데 사용될 Vector객체
int i = 0; // Product배열 item에 사용될 카운터
void buy(Product p) {
if(money<p.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}
money -= p.price; // 가진 돈에서 제품가격을 뺀다.
bonusPoint += p.bonusPoint; // 제품의 보너스포인트를 더한다.
item.add(p); // 제품을 Product[] item에 저장한다.
System.out.println(p+"을/를 구입하셨습니다.");
}
void summary() { // 구매한 물품의 정보를 요약해서 보여준다.
int sum = 0; // 구입한 물품의 가격합계
String itemList =""; // 구입한 물품목록
if(item.isEmpty()) {
System.out.println("구입하신 제품이 없습니다.");
return;
}
//반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
for(int i=0; i<item.size();i++) {
Product p = (Product)item.get(i);
sum+=p.price;
itemList += (i==0)?""+p:", "+p;
}
System.out.println("구입하신 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은 " + itemList + "입니다.");
}
void refund(Product p) {
if(item.remove(p)) {
money+=p.price;
bonusPoint-=p.bonusPoint;
System.out.println(p+"을/를 반품하셨습니다.");
} else {
System.out.println("구입하신 제품 중 해당 제품이 없습니다.");
}
}
}
|
- 구입한 물건을 반환할 수 있는 refund( )메소드를 추가하였다. 메소드 호출 시 구입 물품이 저장되어 있는 item에서 해당 제품을 제거한다.
'언어 > 자바의 정석' 카테고리의 다른 글
[자바의 정석] Chapter 7 객체 지향 프로그래밍II (8) - 인터페이스(interface) (0) | 2021.02.17 |
---|---|
[자바의 정석] Chapter 7 객체 지향 프로그래밍II (7) - 추상클래스(abstract class) (0) | 2021.02.16 |
[자바의 정석] Chapter 7 객체 지향 프로그래밍II (5) - 다형성(polymorphism) (0) | 2021.02.16 |
[자바의 정석] Chapter 7 객체 지향 프로그래밍II (4) - 제어자(modifier) (0) | 2021.02.16 |
[자바의 정석] Chapter 7 객체 지향 프로그래밍II (3) - package와 import (0) | 2021.02.16 |