TIL-23-02-24
Updated:
참조변수와 인스턴스의 연결
- 메서드를 호출할 경우, 참조변수 타입에 관계없이 항상 오버라이딩된 메서드가 호출된다.
- 멤버변수로 호출할 경우, 참조변수의 타입에 따라 달라진다.
- 즉 멤버변수가 조상클래스와 자손클래스에 중복 정의된 경우 조상타입의 참조변수를 사용했을 때는 조상 클래스에 선언된 멤버변수가 사용되고, 자손타입의 멤버변수를 사용했을 때는 자손 클래스에 선언된 멤버변수가 선언된다.
public class BindingTest
{
public static void main(String[] args)
{
Parent p = new Child();
Child c = new Child();
System.out.println("p.x=" + p.x);
p.method();
System.out.println("c.x=" + c.x);
c.method();
}
}
class Parent {
int x = 100;
void method() {
System.out.println("Parent Method");
}
}
class Child extends Parent {
int x = 200;
void method() {
System.out.println("Child Method");
}
}
// 실행결과
p.x=100
Child Method
c.x=200
Child Method
- 이처럼 인스턴스 변수에 직접 접근하면 참조변수의 타입에 따라 사용되는 인스턴스 변수가 달라질 수 있다.
- 따라서 멤버변수들을 주로 private으로 접근을 제한하고, 외부에서는 메서드를 통해서만 멤버변수에 접근할 수 있도록 해야한다.
매개변수의 다형성
- 조상타입의 참조변수를 매개변수로 선언하면, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
- 아래의 예는 Product 클래스가 조상타입이고 Tv, Computer, Audio가 자손타입으로 선언돼있다. Buyer 클래스는 제품을 구입하는 사람이다.
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 포인트 점수
}
class Tv extends Product {}
class Computer extends Product {}
class Audio extends Product {}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스점수
}
- Buyer 클래스에 물건을 구입하는 기능 Buy 메서드를 추가했을 때, 구입할 제품이 필요하므로 매개변수에 구입할 제품을 넘겨받아야 한다. 제품의 종류가 늘어날 때마다 Buy메서드는 계속 추가되어야 한다.
void buy(Computer c) {
money = money - c.price;
bonusPoint = bonusPoint + c.bonusPoint;
}
void buy(Tv t) {
money = money - t.price;
bonusPoint = bonusPoint + t.bonusPoint;
}
- 그러나 메서드의 매겨변수에 다형성을 적용하면 하나의 메서드로 간단히 처리할 수 있다.
void buy(Product p) {
money = money - p.price;
bonusPoint = bonusPoint + p.bonusPoint;
}
- 예제 전체 코드
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price) {
this.price = price;
bonusPoint = (int) (price/10.0); // 보너스점수는 제품가격의 10%
}
}
class Tv extends Product {
Tv() {
// 조상클래스의 생성자 Product (int price) 를 호출한다.
super(100); //Tv의 가격을 100만원으로 한다.
}
// Object클래스의 toString()을 오버라이딩한다.
public String toString () { return "Tv"; }
}
class Computer extends Product {
Computer () { super(200); }
public String toString () { return "Computer"; }
}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스 점수
void buy (Product p) {
if(money < p.price) {
System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
return;
}
money -= p.price; // 가진 돈에서 구입한 제품의 가격을 뺀다.
bonusPoint += p.bonusPoint;
System.out.println(p + "을/를 구입하셨습니다.");
}
}
public class PolyArgumentTest
{
public static void main(String[] args)
{
Buyer b = new Buyer();
b.buy(new Tv());
b.buy(new Computer());
System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
System.out.println("현재 보너스점수는" + b.bonusPoint + "점입니다.");
}
}
여러 종류의 객체를 배열로 다루기
- 조상타입의 배열을 사용하면 자손들의 객체를 한번에 담을 수 있다.
- Product클래스가 Tv, Computer, Audio 클래스의 조상일 때, Product 타입의 참조변수 배열로 처리하면 아래와 같다.
// 기존 코드
Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();
// 배열로 처리
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();
- 앞선 Buyer클래스에 구입한 제품을 저장하기 위한 Product 배열을 추가하면, 구입한 제품을 하나의 배열로 간단히 다룰 수 있다.
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스 점수
Product[] item = new Product[10]; // 구입한 제품을 저장하기 위한 배열
int i = 0; // Product 배열에 사용될 카운터
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 + "을/를 구입하셨습니다.");
}
}
- 예제 전체 코드
class Product {
int price; // 제품의 가격
int bonusPoint; // 제품구매 시 제공하는 보너스점수
Product(int price) {
this.price = price;
bonusPoint = (int) (price/10.0); // 보너스점수는 제품가격의 10%
}
}
class Tv extends Product {
Tv() {
// 조상클래스의 생성자 Product (int price) 를 호출한다.
super(100); //Tv의 가격을 100만원으로 한다.
}
// Object클래스의 toString()을 오버라이딩한다.
public String toString () { return "Tv"; }
}
class Computer extends Product {
Computer () { super(200); }
public String toString () { return "Computer"; }
}
class Buyer { // 고객, 물건을 사는 사람
int money = 1000; // 소유금액
int bonusPoint = 0; // 보너스 점수
Product [] item = new Product[10]; // 구입한 제품을 저장하기 위한 배열
int i = 0; // Product 배열에 사용될 카운터
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] + ", ";
}
System.out.println("구입하는 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은은 " + itemList + "입니다.");
}
}
public class main
{
public static void main(String[] args)
{
Buyer b = new Buyer();
b.buy(new Tv());
b.buy(new Computer());
b.summary();
}
}
java.uti.Vector
- 배열의 크기를 10개 이상 담아야 할 경우, Vector클래스를 사용하면 크기에 제한없이 모든 종류의 객체를 저장할 수 있다.
- Vector 클래스는 내부적으로 Object타입의 배열을 가지고 있기 때문
// 크기가 10인 product 배열
Product[] cart = new Product[10];
//...
void buy(Product p) {
//...
cart[i++] = p;
}
// vector 클래스로 배열 선언
Vector cart = new Vectro();
//...
void buy(Product p) {
//...
cart.add(p);
}
// vector 클래스를 이용한 메서드
void summary() { // 구매한 물품에 대한 정보를 요약해서 보여 준다.
int sum = 0; // 구입한 물품의 가격합계
String itemList = ""; // 구입한 물품목록
if(item.isEmpty()){ //boolean isEmpty()
System.out.println("구입하신 제품이 없습니다.");
return;
}
// 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
for(int i = 0; i <item.size(); i++) {
Product p = (Product)item.get(i); // Vertor의 i번째에 있는 객체를 얻어온다.(Object get(int index) : 형변환 필요)
sum += p.price;
itemList += (i==0) ? "" + p : ", " + p;
}
System.out.println("구입하는 물품의 총금액은 " + sum + "만원입니다.");
System.out.println("구입하신 제품은은 " + itemList + "입니다.");