JAVA_35_다형성

charl hi·2021년 8월 18일
0

JAVA

목록 보기
35/53
  • 자손 instanceof 같 or 조상타입

  • 조상타입 조상 = (조상타입) 자손;

    • ✨✨✨✨보통 조상타입이어야함!!!!!!!!!
    • 좌항과 우항의 타입이 반대거나 상속관계가 아니면 ClassCastException 나옴!!
  • 💖💖티비 티는 스마트티비

  • 💖💖💖인스턴스오브 조상타입

  • ✨✨✨실제 가리키는 객체가 무엇인지 그림그려서 잘 확인하자!!


다형성 (polymorphism)

  • ✨✨✨조상 타입✨✨✨의 참조변수(t)로 자손 타입의 객체(SmartTv)를 다루는 것
    • Tv t = new SmartTv();
    • 조상타입의 참조변수로 ✨✨같은타입인 조상타입을 가리킬지, 아니면 자손타입을 가리킬지 내가 조절하는 것
  • ✨타입 불일치
    -> Tv의 변수 5개, SmartTv의 멤버 5+2=7개
    -> tSmartTv를 참조해도 멤버 7개 중 5개 밖에 사용하지 못한다.


참조변수의 형변환

  • 사용할 수 있는 멤버의 개수를 조절하는 것
  • 조상 - 자손 관계의 참조변수는 서로 형변환 가능
    예)
    • Car - FireEngine, Car - Ambulance끼리 형변환 가능
    • 오해의 소지가 있으므로 삭제
  • (O) Car c = (Car)f;

    cCar타입, fFireEngine타입, 서로 다르므로, f를 조상인 Car타입으로 형변환 해서

    ② 참조변수 f가 가리키는 객체의 주소(FireEngine의 주소)를 참조변수 c에 저장

    cFireEngine을 가리키게 됨.
    -> 그래도 c가 다루는 ✨멤버는 4개

  • (O) FireEngine f2 = (FireEngine)c;
    : 자손인 FireEngine타입으로 형변환
    : 참조변수 c가 가리키는 객체의 주소(FireEngine의 주소)를 참조변수 f2도 저장해 가리킴
    : f2가 다루는 멤버는 ✨다시 5개로

✨✨✨✨주의

  • FireEngine f2 = (FireEngine)c;
    -> 가 가능했던 건 ✨✨✨cFireEngine타입이기 때문이다.
    -> 만약 ✨✨✨cCar타입이었다면 ClassCastException!!!!

  • (X) Ambulance a = (Ambulance)f;
    : 상속관계가 아닌 클래스 간의 형변환 불가



class Car {
	String color;	// 멤버 4개
	int door;
	
	void drive() {	// 운전하기
		System.out.println("drive, brrr...");
	}
	void stop() {	// 멈추기
		System.out.println("stop!!!");
	}
}

class FireEngine extends Car {
	// 멤버 4+1 = 5개
	void water() {	// 물뿌리기
		System.out.println("water~~~");
	}
}


public class Ex7_07 {

	public static void main(String[] args) {
		// 다형성
		// 그림1
		Car car = null;	// 참조변수car에 null로 초기화
		FireEngine fe = new FireEngine();	//리모콘 5개
		FireEngine fe2 = null;
		
		fe.water();
		// 그림2
		car = (Car)fe;	// (Car)생략 가능	-> 리모콘 4개
//		car.water();	// car는 water()사용 불가능!!
		fe2 = (FireEngine)car;	// 생략 불가능	-> 리모콘 4개
		fe2.water();

	}

}

water~~~
water~~~

그림1

그림2



형변환 시 주의점

  • 형변환할 때 ✨실제 인스턴스가 무엇인지(멤버 개수, null인지, 어떤 객체를 가리키는지 등등)✨ 잘 알아야 한다.

✔ 다음은 에러


public class Ex7_07 {

	public static void main(String[] args) {
		Car car = new Car();
		FireEngine fe = (FireEngine)car;	
		// -> 컴파일 ok이지만 형변환 실행 에러 java.lang.ClassCastException
		fe.water();   // 컴파일 ok이지만
	}
}

  • 그림 잘못됐는데.... 형변환 가능하고, 저 객체 가리키는게 가능하다. 빨간 엑스 삭제!

  • 이런 상태이기 때문에 ✨형변환은 가능한데 fe가 ✨✨water()를 호출을 못한다.



참조변수의 형변환을 하는 이유

  • ✨✨✨참조변수를 변경함으로써 사용할 수 있는 멤버의 개수를 조절하기 위해


instanceof 연산자

  • 참조변수를 형변환하기 전에 형변환 가능여부를 확인할 때
  • 가능하면 true반환
  • ✨✨참조변수를 형변환하기 전에 반드시 instanceof로 확인 해줘야 한다.
참조변수a instanceof 타입B

: 참조변수a의 타입이 타입B로 형변환 가능한가?
: 참조변수a가 가리키는 객체가 타입B이냐? 또는 타입B의 자손이냐?

true
참조변수a instanceof 타입A : 타입이 자기자신으로 같으면
참조변수a instatnceof 조상타입

false : no, 그 외에 다!

  • ✨✨자손참조변수 instanceof 자기자신타입 또는 조상타입 은 언제나 true!!
Car c = new Car();
FireEngine f = new FireEngine();
		
boolean b = c instanceof FireEngine;
System.out.println(b);	//false
		
c = (FireEngine)f;
boolean o = c instanceof FireEngine;
System.out.println(o);	//true


void doWork(Car c) {
	if (c instanceof FireEngine) {
    //FireEngine이 매개변수와 같은타입 또는 조상타입이냐?
		FireEngine fe = (FireEngine)c;
		//true면 객체생성하고 그 참조변수fe에 매개변수의 객체주소를 넣어라.
		fe.water();
	}
}

이런 식으로 쓰인다는데.. 익숙해지자

doWork(Car c);
doWork(new Car());
doWork(new FireEngine());
doWork(new Ambulance());
//Car 또는 Car의 모든 자손들 가능
//여기서 
doWork(new FireEngine()); 	//객체생성 후 바로 넣기
//은 아래와 동일하다.
Car c = new FireEngine();	//객체생성 후 참조변수를 만들어 받고 매개변수로 넣기
doWork(c);

Ch07Re

class Car{
	String color;
	int door;
	
	void drive() {
		System.out.println("drive: brr...");
	}
	
	void stop() {
		System.out.println("stop!!!");
	}
}

class FireEngine extends Car{
	void water() {
		System.out.println("water~~~");
	}
}

class Am extends Car{

}

class Change{
	static void doWork(Car cc) {
		//Car와 그 자손들, 즉 Car c, FireEngine f, FireEngine ff 등 가능, 매개변수의 다형성!
		if(cc instanceof FireEngine) {	//cc의 타입이 FE 또는 FE의 자손이면 true
			FireEngine fe = (FireEngine) cc;	//매개변수로 들어온 주소를 왼쪽항에 저장
			fe.water();
		} else {
			System.out.println("nope!");
		}
	}
}


public class Ex7_07 {

	public static void main(String[] args) {
		//water~~~
		FireEngine f = new FireEngine();
		Change.doWork(f);	//가리키는 객체인 FE가 매개변수로 ->true
		
		Car c = new FireEngine();
		Change.doWork(c);	//가리키는 객체인 FE가 매개변수로 ->true
		
		Change.doWork(new FireEngine());	//타입 FE가 매개변수로 ->true
		
		//nope!
		Change.doWork(new Am());	//타입Am가 매개변수로 ->false
		Change.doWork(new Car());	//타입Car가 매개변수로 ->false
		
		Car cc = new Car();
		FireEngine ff = new FireEngine();
		
		boolean b = cc instanceof FireEngine;	//cc의 타입이 Car->false
		System.out.println(b);
		
		//false여도 상속관계&&아래의 경우면 형변환 가능하다!
		cc = (Car)ff;
//		ff = (FireEngine) cc;	이건 안돼!!! ClassCastException
		boolean o = cc instanceof FireEngine;	//cc의 타입이 FE->true
		System.out.println(o);

	}

}

water~~~
water~~~
water~~~
nope!
nope!


public class Ex7_07 {

	public static void main(String[] args) {

		FireEngine fe = new FireEngine();	
		
		System.out.println(fe instanceof Object);	// 조상이면 뭐든 true
		System.out.println(fe instanceof Car);
		System.out.println(fe instanceof FireEngine);	// 자기자신도 true
		
		fe.water();

//
		Car car = new Car();
		
		System.out.println(car instanceof Object);
		System.out.println(car instanceof Car);
		System.out.println(car instanceof FireEngine);	// car의 타입 Car는 FireEngine 또는 FireEngine의 자손이 아니므로 false
        							
		fe.water();
        
//        
		car = (Car)fe;	// 그러나 주소를 이렇게 바뀐다면?
        			// 즉 car는 FireEngine을 가리켜 주소값을 저장하게 된다. car의 타입은 FireEngine!
	
		System.out.println(car instanceof Object);
		System.out.println(car instanceof Car);		// FE -- Car -> Car가 조상이므로 -> true
		System.out.println(car instanceof FireEngine);	// 자기자신을 가리키게 되므로 true
		
		fe.water(); 			
	}

}

true
true
true
water~~~
true
true
false
water~~~
true
true
true
water~~~

아이구 어렵다. 복습하자.

instanceof




Ref

0개의 댓글

관련 채용 정보