본문 바로가기
👨‍🏫Study/JAVA

[JAVA] 07 - 2 타입 변환과 다형성

by 코푸는 개발자 2022. 3. 21.
728x90
다형성 간단히 설명

 

- 다형성 : 다양한 객체를 통해 다양한 실행결과를 출력시킴

- 다형성의 예 : 모든 타이어는 달리게 해주는 기능이 들어있지만 어떤 타이어를 장착하느냐에 따라 주행 성능이 달라짐

- 예를 들어 자동차는 한국타이어와 금호타이어 중에서 타이어 타입을 선택하고 각 타이어 마다 성능은 다르게 나온다.

- 다형성을 구현하려면 메소드 재정의 + 타입변환이 필요하다.

 

 

자동 타입변환

 

- 클래스에서의 타입 변환은 상속 관계에 있는 클래스 사이에서 발생하며 자식이 부모 타입으로 자동 변환이 가능하다. 

- 자동 타입 변환 (=promotion)은 프로그램 실행 도중에 자동적으로 일어나는 타입 변환을 말함

- 자동 타입 변환 형태 : 부모타입 변수 = 자식타입;

- 자동 타입 변환 개념 : 자식이 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급된다는 의미를 가짐

- 예시

class Animal {} // 부모 클래스
class Cat extends Animal {} // 자식 클래스

 

Cat cat = new Cat();
Animal animal = cat; // 자동 타입 변환
Animal animal = new Cat();

- 메모리 상태 :  cat 변수와 animal 변수는 각각 타입은 다르지만 둘다 Cat 객체를 참조한다. 

- 실제로 == 연산시 true 가 나오며 이는 두 변수가 동일한 객체를 참조함을 의미한다.

 

자동 타입변환 예제

 

class A {} // 조상

class B extends A {} // B = A의 자식
class C extends A {} // C = A의 자식

class D extends B {} // D = B의 자식, A의 손자
class E extends C {} // E = C의 자식, A의 손자

public class PromotionExample {
	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 = d; // 부모 타입으로 자동 타입 변환
		C c1 = e; // 부모 타입으로 자동 타입 변환
		
		// B b2 = e; // B와 E는 상속 관계에 있지 않으므로 에러 발생
		// C c2 = d; // C와 D는 상속 관계에 있지 않으므로 에러 발생
	}
}

 

재정의된 메소드로의 접근

 

- 부모 타입으로 자동 타입 변환이 되면 부모 클래스의 필드와 메소드만 접근이 가능함

- 비록 변수가 자식 객체를 참조하지만 접근 가능한 멤버는 부모 클래스 멤버만 가능

- 그러나 부모 클래스의 메소드가 자식 클래스에서 재정의되었다면 메소드 호출시 자식 클래스의 메소드가 대신 호출됨

 (이것이 바로 다형성의 개념)

 

재정의된 메소드로의 접근 예제

 

public class Parent {
	//메소드
	public void method1() {
		System.out.println("Parent-method1()");
	}
	public void method2() {
		System.out.println("Parent-method2()");
	}
}

 

public class Child extends Parent {
	@Override
	public void method2() {
		System.out.println("Child-method2()"); // method2는 재정의된 메소드임
	}
	public void method3() {
		System.out.println("Child-method3()");
	}
}

 

public class ChildExample {
	public static void main(String[] args) {
		Child child = new Child(); 
		
		Parent parent = child; // 자동 타입 변환
		parent.method1(); // Parent-method1() 출력
		parent.method2(); // 재정의된 메소드가 호출됨 -> Child-method2() 출력
		// parent.method3(); // 호출 불가능
	}
}

 

 

필드의 다형성

 

1. Tire 클래스

public class Tire {
	// 필드
	public int maxRotation;			// 최대 회전수(타이어 수명)
	public int accumulatedRotation;	// 누적 회전수
	public String location;			// 타이어의 위치
	
	// 생성자
	public Tire(String location, int maxRotation) {
		this.location = location; // 초기화
		this.maxRotation = maxRotation; // 초기화
	}
	
	//메소드
	public boolean roll() {
		++accumulatedRotation; // 누적 회전수 1 증가
		if(accumulatedRotation < maxRotation) { 
			System.out.println(location + " Tire 수명: " + (maxRotation-accumulatedRotation) + "회");
			return true; // 정상회전(누적<최대)일 경우 실행
		} else {
			System.out.println("*** " + location + " Tire 펑크 ***");
			return false; // 펑크(누적=최대)일 경우 실행
		}
	}
}

 

2. Car 클래스

public class Car {
	//필드
	Tire frontLeft = new Tire("앞 왼쪽", 6); // 자동차에 4개의 타이어 객체 생성
	Tire frontRight = new Tire("앞 오른쪽", 2); 
	Tire backLeft = new Tire("뒤 왼쪽", 3); 
	Tire backRight = new Tire("뒤 오른쪽", 4);
	//생성자
	
	//메소드
	int run() {
		System.out.println("[자동차가 달립니다.]"); 
		// 모든 타이어가 1회씩 실행되어야 하므로 각 Tire 객체의 roll() 메소드를 호출
		// false(펑크)를 리턴하는게 나오면 stop() 메소드 호출 후 해당 타이어 번호를 리턴
		if(frontLeft.roll() == false) {stop(); return 1;}
		if(frontRight.roll() == false) {stop(); return 2;}
		if(backLeft.roll() == false) {stop(); return 3;}
		if(backRight.roll() == false) {stop(); return 4;}
		return 0;
	}
	
	void stop() {
		System.out.println("[자동차가 멈춥니다.]"); // 펑크났을때 실행 
	}
}

 

3. Tire의 자식 클래스

public class HankookTire extends Tire {
	//생성자
	public HankookTire(String location, int maxRotation) {
		super(location, maxRotation);
	}
	
	//메소드
	@Override // 조금 다르게 내용을 출력하려고 roll() 메소드를 재정의함
	public boolean roll() {
		++accumulatedRotation;
		if(accumulatedRotation < maxRotation) {
			System.out.println(location + " HankookTire 수명: " + (maxRotation - accumulatedRotation) + "회");
			return true;
		} else {
			System.out.println("*** " + location + " HankookTire 펑크 ***");
			return false;
		}
	}
}

 

public class KumhoTire extends Tire {
	//생성자
	public KumhoTire(String location, int maxRotation) {
		super(location, maxRotation);
	}
	
	//메소드
	@Override // 조금 다르게 내용을 출력하려고 roll() 메소드를 재정의함
	public boolean roll() {
		++accumulatedRotation;
		if(accumulatedRotation < maxRotation) {
			System.out.println(location + " kumhoTire 수명: " + (maxRotation - accumulatedRotation) + "회");
			return true;
		} else {
			System.out.println("*** " + location + " KumhoTire 펑크 ***");
			return false;
		}
	}
}

 

4. CarExample 클래스(실행 클래스)

public class CarExample {
	public static void main(String[] args) {
		Car car = new Car(); // Car 객체 생성
		
		for(int i=1; i<=5; i++) { // Car 객체의 run() 메소드 5번 반복 실행
			int problemLocation = car.run();
		
			switch(problemLocation) {
			case 1: // 앞 왼쪽 타이어가 펑크났을때 HankookTire로 교체
				System.out.println("앞 왼쪽 타이어를 HankokTire로 교체");
				car.frontLeft = new HankookTire("앞 왼쪽", 15);
				break;
			case 2: // 앞 오른쪽 타이어가 펑크났을때 KumhoTire로 교체
				System.out.println("앞 오른쪽 타이어를 KumhoTire로 교체");
				car.frontRight = new KumhoTire("앞 오른쪽", 13);
				break;
			case 3: // 뒤 왼쪽 타이어가 펑크났을때 HankookTire로 교체
				System.out.println("뒤 왼쪽 타이어를 HankokTire로 교체");
				car.backLeft = new HankookTire("뒤 왼쪽", 14);
				break;
			case 4: // 뒤 오른쪽 타이어가 펑크났을때 KumhoTire로 교체
				System.out.println("뒤 오른쪽 타이어를 KumhoTire로 교체");
				car.backRight = new KumhoTire("뒤 오른쪽", 17);
				break;
			} 
			System.out.println("------------------------------------");
		}
	}
}

 

5. 출력 결과

[자동차가 달립니다.]
앞 왼쪽 Tire 수명: 5회
앞 오른쪽 Tire 수명: 1회
뒤 왼쪽 Tire 수명: 2회
뒤 오른쪽 Tire 수명: 3회
------------------------------------
[자동차가 달립니다.]
앞 왼쪽 Tire 수명: 4회
*** 앞 오른쪽 Tire 펑크 ***
[자동차가 멈춥니다.]
앞 오른쪽 타이어를 KumhoTire로 교체
------------------------------------
[자동차가 달립니다.]
앞 왼쪽 Tire 수명: 3회
앞 오른쪽 kumhoTire 수명: 12회
뒤 왼쪽 Tire 수명: 1회
뒤 오른쪽 Tire 수명: 2회
------------------------------------
[자동차가 달립니다.]
앞 왼쪽 Tire 수명: 2회
앞 오른쪽 kumhoTire 수명: 11회
*** 뒤 왼쪽 Tire 펑크 ***
[자동차가 멈춥니다.]
뒤 왼쪽 타이어를 HankokTire로 교체
------------------------------------
[자동차가 달립니다.]
앞 왼쪽 Tire 수명: 1회
앞 오른쪽 kumhoTire 수명: 10회
뒤 왼쪽 HankookTire 수명: 13회
뒤 오른쪽 Tire 수명: 1회
------------------------------------

 

 

매개 변수의 다형성

 

1. 부모 클래스 Vehicle

public class Vehicle { // 매개변수의 타입을 만듬
	public void run() {
		System.out.println("차량이 달립니다.");
	}
}

 

2. Vehicle을 이용하는 또다른 클래스

public class Driver {
	//Vehicle 타입의 매개값을 받는 drive() 메소드 선언
	public void drive(Vehicle vehicle) { 
		vehicle.run(); 
	}
}

 

3. 자식 클래스 Bus와 Taxi

public class Bus extends Vehicle { // Vehicle 클래스로부터 상속받음
	@Override
	public void run() { // 원래 Vehicle 클래스에 있던 run() 메소드를 오버라이딩함
		System.out.println("버스가 달립니다.");
	}
}
public class Taxi extends Vehicle { // Vehicle 클래스로부터 상속받음
	@Override
	public void run() { // 원래 Vehicle 클래스에 있던 run() 메소드를 오버라이딩함
		System.out.println("택시가 달립니다.");
	}
}

 

4. 실행 클래스

public class DriverExample {
	public static void main(String[] args) {
		Driver driver = new Driver();
		Bus bus = new Bus();
		Taxi taxi = new Taxi();
		
		// 매개변수로 vehicle을 받아야하는데 Vehicle의 자식 객체인 bus와 taxi를 받음
		// 자동 타입변환된 것임
		driver.drive(bus); // Vehicle vehicle = bus;
		driver.drive(taxi); // Vehicle vehicle = taxi;
	}
}

 

5. 출력 결과

버스가 달립니다.
택시가 달립니다.

- drive() 메소드를 실행하면 Vehicle의 run()이 출력되도록 코드를 짰는데 실제로 drive() 메소드를 호출하면 Bus와 Taxi에서 오버라이딩된 run() 메소드가 출력이 된다.

- 이 말은 매개값이 자동 타입 변환이 되었음을 의미한다.

- 그렇다면 우리는 메소드 재정의를 이용해서 매개 변수의 다형성을 구현해본 것이다.

 

강제 타입 변환

 

- 부모 타입을 자식 타입으로 변환하는 것을 말함

- 모든 부모 타입을 자식 타입으로 강제 변환할 수 있는 건 아님

- 자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때만 가능하다.

-  형태

Parent parent = new Child(); // 자동 타입 변환
Child child = (Child) parent; // 강제 타입 변환

- 강제 타입 변환이 필요한 이유 : 자식 타입이 부모으로 자동 타입 변환되면 부모에 선언된 필드와 메소드만 사용 가능하다.

- 만약 다시 자식의 필드와 메소드를 사용하고 싶다면 강제 타입 변환을 해주면 사용이 가능하다.

 

 

강제 타입 변환 예제

 

public class Parent {
	//필드
	public String field1;
	
	//메소드
	public void method1() {
		System.out.println("Parent-method1()");
	}
	public void method2() {
		System.out.println("Parent-method2()");
	}
}

 

public class Child extends Parent {
	public String field2;
	
	public void method3() {
		System.out.println("child-method3()");
	}
}

 

public class ChildExample {
	public static void main(String[] args) {
		Parent parent = new Child(); // 자동 타입 변환
		parent.field1 = "data1";
		parent.method1();
		parent.method2();
		// parent.field2 = "data2"; // 불가능
		// parent.method3(); // 불가능
		
		Child child = (Child) parent;
		child.field2 = "data2"; // 가능
		child.method3(); // 가능
	}
}

 

객체 타입 확인 (instanceof 연산자)

 

- 강제 타입 변환은 자식 타입이 부모 타입으로 자동 타입 변환이 된 경우만 사용이 가능하므로

- 아래와 같이 처음부터 부모 타입으로 생성된 객체는 강제 타입 변환이 불가능하다.

Parent parent = new Parent(); // 애초에 부모 타입으로 생성된 객체이므로
Child child = (child) parent; // 강제타입변환이 불가능하다

 

- instanceof 연산자 : 강제 타입 변환을 할 수 있는지 없는지 확인하기 위해 사용한다.

- 형태 

boolean result = 객체 instanceof 타입

 

- 객체 타입 확인 (instanceof 연산자) 예제

public class Parent {}
public class Child extends Parent{}
public class InstanceofExample {
	
	//타입변환이 가능한지 확인하는 메소드
	public static void method1(Parent parent) {
		if(parent instanceof Child) {
			Child child = (Child) parent;
			System.out.println("method1 - Child로 변환 성공");
		} else {
			System.out.println("method1 - Child로 변환되지 않음");
		}
	}
	
	//타입변환이 가능한지 확인하지 않고 그냥 바로 변환하는 메소드 
	public static void method2(Parent parent) {
		Child child = (Child) parent; // classCastException 에러가 발생할 수도 있음
		System.out.println("method1 - Child로 변환 성공");
	}
	
	public static void main(String[] args) {
		Parent parentA = new Child(); // 먼저 자동형변환 해주기
		method1(parentA); // Child 객체를 매개값으로 전달
		method2(parentA); // 강제형변환이 가능한 경우이므로 method1,2 둘다 에러X
		
		Parent parentB = new Parent(); // 그냥 Parent 타입으로 받음
		method1(parentB); // Parent 객체를 매개값으로 전달하며 강제형변환 불가하다고 뜸
		method2(parentB); // 예외 발생 -> 강제형변환이 안되는 경우이며 그마저도 타입변환이 가능한지 확인해보지도 않아서 예외가 발생
	}
}
method1 - Child로 변환 성공
method1 - Child로 변환 성공
method1 - Child로 변환되지 않음
Exception in thread "main" java.lang.ClassCastException

- Child 객체를 매개값으로 받으면 두 메소드 모두 예외가 발생하지않음

- 하지만 Parent 객체를 매개값으로 전달하면 method2()에서는 ClassCastException이 발생한다.

- 무조건 변환하려고 하면 안되고 method1() 처럼 강제 타입 변환이 가능한지 instanceof 연산자로 확인을 해보는 작업이 필요하다.

- ClassCastException 예외가 발생하면 프로그램이 즉시 종료되어버린다.

 

 

다형성 추가 예제 - Friend 배열 만들기 (상속 클래스 사용 안한 버전)

 

// 대학 친구
class UnivFriend1 {
	// 필드
	private String name;
	private String major;
	private String phone;

	// 생성자
	public UnivFriend1(String na, String ma, String ph) {
		name = na;
		major = ma;
		phone = ph;
	}

	// 메소드
	public void showInfo() {
		System.out.println("이름 : " + name);
		System.out.println("전공 : " + major);
		System.out.println("전화번호 : " + phone);
	}
}

// 직장 동료
class CompFriend1 {
	// 필드
	private String name;
	private String department;
	private String phone;

	// 생성자
	public CompFriend1 (String na, String de, String ph) {
		name = na;
		department = de;
		phone = ph;
	}

	// 메소드
	public void showInfo() {
		System.out.println("이름 : " + name);
		System.out.println("부서 : " + department);
		System.out.println("전화번호 : " + phone);
	}
}

 

<실행 클래스>

public class MyFriends_not_Inherited {
	public static void main(String[] args) {
		// 대학 친구의 관리를 위한 배열과 변수
		UnivFriend[] uf = new UnivFriend[3];
		int uc = 0;

		// 직장 동료의 관리를 위한 배열과 변수
		CompFriend[] cf = new CompFriend[3];
		int cc = 0;

		// 대학친구 추가
		uf[uc++] = new UnivFriend("kim", "computer", "010-1");
		uf[uc++] = new UnivFriend("lee", "electronics", "010-2");
		uf[uc++] = new UnivFriend("seo", "Math", "010-3");

		// 직장동료 추가
		cf[cc++] = new CompFriend("kim", "R&D", "010-1");
		cf[cc++] = new CompFriend("lee", "R&D", "010-2");
		cf[cc++] = new CompFriend("seo", "R&D", "010-3");

		for(int i=0; i<uf.length; i++) {
			uf[i].showInfo();
			System.out.println();
		}

		for(int i=0; i<cf.length; i++) {
			cf[i].showInfo();
			System.out.println();
		}
	}
}

 

<출력 결과>

이름 : kim
전화번호 : 010-1
전공 : computer

이름 : lee
전화번호 : 010-2
전공 : electronics

이름 : seo
전화번호 : 010-3
전공 : Math

이름 : kim
전화번호 : 010-1
부서 : R&D

이름 : lee
전화번호 : 010-2
부서 : R&D

이름 : seo
전화번호 : 010-3
부서 : R&D

 

 

다형성 추가 예제 - Friend 배열 만들기 (상속 클래스 사용 버전)

 

<부모 클래스>

class Friend {
	// 필드
	public String name;
	public String phone;

	// 생성자
	public Friend(String na, String ph) {
		name = na;
		phone =ph;
	}

	// 메소드
	public void showInfo() {
		System.out.println("이름 : " + name);
		System.out.println("전화번호 : " + phone);
	}
}

 

<자식 클래스 1>

class UnivFriend extends Friend {
	// 필드
	public String major;
	
	// 생성자
	public UnivFriend(String na, String ma, String ph) {
		super(na, ph);
		major =ma;
	}
	
	// 메소드
	@Override
	public void showInfo() {
		super.showInfo();
		System.out.println("전공 : " + major);
	}
}

 

<자식 클래스 2>

class CompFriend extends Friend{
	// 필드
	public String department;
	
	// 생성자
	public CompFriend(String na, String de, String ph) {
		super(na, ph);
		department = de;
	}
	
	// 메소드
	@Override
	public void showInfo() {
		super.showInfo();
		System.out.println("부서 : " + department);
	}
}

 

<실행 클래스>

public class MyFriends {
	public static void main(String[] args) {
		Friend[] friends = new Friend[6];
		int count=0;
		
		// 대학친구 추가
		friends[count++] = new UnivFriend("kim", "computer", "010-1");
		friends[count++] = new UnivFriend("lee", "electronics", "010-2");
		friends[count++] = new UnivFriend("seo", "Math", "010-3");
		
		// 직장동료 추가
		friends[count++] = new CompFriend("kim", "R&D", "010-1");
		friends[count++] = new CompFriend("lee", "R&D", "010-2");
		friends[count++] = new CompFriend("seo", "R&D", "010-3");
		
		for(int i=0; i<friends.length; i++) {
			friends[i].showInfo();
			if(friends[i].name == "kim") {
				System.out.println("kim 을" + i+1 + "번째에서 찾았습니다.");
			} System.out.println();
		}
        
	}
}

 

 

<출력 결과>

이름 : kim
전화번호 : 010-1
전공 : computer
kim 을01번째에서 찾았습니다.

이름 : lee
전화번호 : 010-2
전공 : electronics

이름 : seo
전화번호 : 010-3
전공 : Math

이름 : kim
전화번호 : 010-1
부서 : R&D
kim 을31번째에서 찾았습니다.

이름 : lee
전화번호 : 010-2
부서 : R&D

이름 : seo
전화번호 : 010-3
부서 : R&D

 

 

다형성 추가 예제 -  phone 클래스

 

<부모 클래스>

class MobilePhone {
	// 필드
	protected String number;
	
	// 생성자
	public MobilePhone(String num) {
		this.number = num;
	}
	
	// 메소드
	public void receive() {
		System.out.println("Hi~from " + this.number);
	}	
}

 

<자식 클래스>

class SmartPhone extends MobilePhone {
	// 필드
	private String androidVer;
	
	// 생성자
	public SmartPhone(String num, String ver) {
		super(num);
		androidVer = ver;
	}
	
	// 메소드
	public void send(String number) {
		System.out.println("Hello~to " + number);
	}
	
	public void playApp() {
		System.out.println("App is runnung in " + androidVer);
	}
	
	@Override
	public void receive() {
		super.receive();
		System.out.println("I am smart");
	}
}

 

<실행 클래스>

public class MobileSmartPhone {
	public static void main(String[] args) {
    	// 스마트폰 객체 생성
		SmartPhone phone1 = new SmartPhone("010-2","Ios 7.0");
		MobilePhone phone2 = new SmartPhone("010-3","Ios 14.7.1");
		
        //전화걸기
		phone1.send("010-1"); // Hello~to 010-1 -> 자식 클래스의 메소드 호출
		// phone2.send("010-1"); // 컴파일 에러
		// 부모 타입으로 자동 타입 변환된 참조 변수인 phone2로 자식 클래스 소속 메소드(send())를 호출할 수 없다.
		
		//전화받기
		phone1.receive(); // Hi~from 010-2 I am smart -> 자식 클래스 메소드가 호출됨
		phone2.receive(); // Hi~from 010-3 I am smart 
		// -> 부모 타입으로 자동 타입 변환된거지만 receive() 메소드는 애초에 부모 클래스에도 있어서 호출이 되는 것임
		// 그런데 자식 클래스에서 메소드 재정의를 했기 때문에 재정의된 메소드가 호출되는 것이다.
		
        //앱을 선택하여 실행하기
		phone1.playApp(); // App is runnung in Ios 7.0
		// phone2.playApp(); // 컴파일 에러
		// 부모 타입으로 자동 타입 변환된 참조 변수인 phone2로 자식 클래스 소속 메소드(playApp())를 호출할 수 없다.
	}
}

 

<출력 결과>

Hello~to 010-1
Hi~from 010-2
I am smart
Hi~from 010-3
I am smart
App is runnung in Ios 7.0

 

 

다형성 추가 예제 - Wrapping 클래스

 

public class Wrapping {
	public static void main(String[] args) {
		// 객체 생성
		Box box1 = new Box();
		PaperBox box2 = new PaperBox();
		GoldPaperBox box3 = new GoldPaperBox();

		// 메소드 호출
		wrapBox(box1); //true false false
		wrapBox(box2); // true true false
		wrapBox(box3); // true true true 
	}

	// 메소드 선언
	private static void wrapBox(Box box) {
		System.out.println(box instanceof Box);
		System.out.println(box instanceof PaperBox);
		System.out.println(box instanceof GoldPaperBox);
		System.out.println();
	}
}

class Box {}
class PaperBox extends Box{}
class GoldPaperBox extends PaperBox{}

 

 

다형성 추가 예제 - CakeControlCode 클래스

 

class Cake {
	// 메소드
	public void sweet() {System.out.println("Cake.sweet()");}
	public void send() {System.out.println("Cake sending....");}
}

class CheeseCake extends Cake {
	// 메소드
	public void milky() {System.out.println("CheeseCake.milky()");}
	@Override // 메소드 오버라이딩
	public void send() {System.out.println("CheeseCake Sending....");}
}

class StrawberryCheeseCake extends CheeseCake {
	// 메소드
	public void sour() {System.out.println("StrawberryCheeseCake.sour()");}
	@Override // 메소드 오버라이딩
	public void send() {System.out.println("StrawberryCheeseCake sending....");}
}

 

<실행 클래스>

public class CakeControlCode {
	public static void main(String[] args) {
		// StrawberryCheeseCake 인스턴스는 Cake과 CheeseCake의 인스턴스다.
		Cake cake1 = new StrawberryCheeseCake(); // 딸기치즈케익을 케익 타입으로 자동 타입 변환
		CheeseCake cake2 = new StrawberryCheeseCake(); // 딸기치즈케익을 치즈케익 타입으로 자동 타입 변환
		
		cake1.sweet(); // Cake.sweet()
		cake2.milky(); // CheeseCake.milky()
		cake2.sweet(); // Cake.sweet() -> 더 상위 클래스의 메소드는 호츌이 된다.
		
		// 참조변수 간 대입과 형변환
		CheeseCake cake3 = new CheeseCake();
		Cake cake4 = cake3; // 자동 형변환
		
		Cake cake5 = new CheeseCake();
		// CheeseCake cake6 = cake5; // 불가능함. 이미 Cake 타입으로 형변환된 상태이므로. 
		CheeseCake cake6 = (CheeseCake)cake5;
		 
		// 일괄처리 (배열 관점)
		Cake[] cakes = new Cake[3]; // 배열 안에 참조를 넣음
		
		cakes[0] = new Cake();
		cakes[1] = new CheeseCake();
		cakes[2] = new StrawberryCheeseCake();
		
		for(int i=0; i<cakes.length; i++) {
			cakes[i] = new CheeseCake(); // 이 과정을 꼭 거쳐야함. cakes의 각 방에 CheeseCake 객체를 넣어준다.
			cakes[i].send();
		}
	}	
}

 

728x90

'👨‍🏫Study > JAVA' 카테고리의 다른 글

[JAVA] 08 - 1 인터페이스  (0) 2022.03.21
[JAVA] 07 - 3 추상 클래스  (0) 2022.03.21
[JAVA] 07 - 1 상속  (0) 2021.08.11
[JAVA] 06 - 6 패키지와 접근 제한자  (0) 2021.08.06
[JAVA] 06 - 5 인스턴스 멤버와 정적 멤버  (0) 2021.08.06

댓글