Java/모두의 자바

Chapter 07-42 클래스 형변환

계란💕 2022. 2. 9. 00:57

07-42.1  클래스 형변환

 

  - 기본형의 형을 바꾼 것처럼 클래스형의 형도 바꿀 수 있다. 

   Ex) 

Car car = new Van();

  - Car를 가리키겠다고 선언한 car형 변수인데 Van 가리키고 있다. 

  - 묵시적 형변환이 일어나서 오류가 발생하지않는다.

  - 클래스는 부모 객체가 항상 더 큰 그릇이라고 생각하면 된다. 

  - 형변환 하는 이유는?

    -> 부모가 자식을 가리킬 수 있으나 부모가 알고 있는 메서드 까지만 접근할 수 있기 때문이다. 

    -> 이 때, 형변환으로 객체가 가진 모든 부분을 사용한다.

 

  (1) 묵시적(암묵적) 형변환: 큰 그릇에 작은 그릇의 값을 담는 경우

  - 오류가 발생하지 않는다.

 

  (2) 명시적 형변환: 작은 그릇에 큰 그릇의 값을 담는 경우

  - 큰 그릇에 들어있는 값에 따라서 실행 시점에 오류가 발생할 수 있다. 

  - 따라서, 프로그래머에세 명시적으로 형변환할 것을 요구한다.

 

 

07-42.2 형변환 예제

 

  (1) Car클래스에 run메서드 추가

<hide/>
package javaStudy;
public class Car{
	public void run() {
		System.out.println("Car의 run메서드");
	}
}

  (2) Car클래스를 상속 받는 Van클래스

<hide/>
package javaStudy;

public class Van extends Car {
	public void ppangppang() {
		System.out.println("빵빵");
	}
}

  - Van에는 Car에 없는 ppangppang 메서드가 있다.

  - 둘의 상속 관계가 있으니 Van객체를 Car형의 참조 변수로 참조할 수 있다. 

  - 부모 타입 으로 자식 객체를 참조하게 되면 부조가 가진 메서드만 이용 가능하다. 

 

  (3) VanExam 에서 실행한다.

<hide/>
package javaStudy;

public class VanExam {
	public static void main(String[] args) {
		Car c = new Van();
		c.run();	
	}
}

  Note) 실행결과: Car의 run 메서드

  - Car c = new Van(); 을 보면 Car형 변수 c가 Van의 인스턴스를 가리킨다.

  - 묵시적 형변환이 일어난다.

  - 객체들 사이에상속이 일어나면 부모형 그릇에 그 부모를 상속 받은 자식들, 그 자식의 자식들도 모두 담을 수 있다. 

  - 기본 자료형과 다르게 참조(레퍼런스 ) 자료형은 실제 값이 아니라 주소를 가지므로  '가리킨다'고 표현 한다.

  - 부모 타입인 Car라는 형으로 자식 타입인 Van을 가리킬 수 있다는 뜻이다.

  - Car형의 레퍼런스 변수 c는 Car가 가진 run이라는 메서드를 사용하는데 문제가 없다.

  - Car형 이기는 하지만 실제로 생성된 객체는Van이다.(new Van)

  - Van에는 run외에도 ppangppang 메서드를 사용할 수 있다.

 

  (4)

<hide/>
package javaStudy;

public class VanExam {
	public static void main(String[] args) {
		Car c = new Van();
		c.run();	
//		c.ppangppang();
		
		Van van = (Van)c;
		van.run();
		van.ppangppang();
		
	}
}

  -  c뒤에 마침표를 찍으면 사용 가능한 메서드가 많지만 ppangppang은 나오지 않는다

  - 또, 실행하면 에러가 난다.

  - 부모 타입으로 자식을 가리킬 수는 있지만 부모 타입으로 자식을 

  - Van객체에는 ppangppang메서드가 있다.

  - 하지만, 부모 타입으로 가리키고 있어서 ppangppang을 사용할 수 없다. 

  - 이럴 때 형변환하면 이 기능을 사용할 수 있다. 

  - Car c = new Van() : Car타입(부모)이 Van타입(자식)을 가리키고 있다.

    -> 아무 문제 없다. (Car는 Van보다 상위 개념)

 

  - Van van = c : Van타입으로 묶어서 c를 가리키려고 하면 에러가 난다. 

  - c는 Car형이기 때문에 그보다 작은 Van형이 가리킬 수는 없다.

  - Car에 어떤 차가 올지 알 수 없다. 

  - 기본형 변수에서 큰 그릇에 있는 것을  작은 그릇으로 옮길 때, 그릇의 크기를 알면 강제로 형변환 할 수 있다.

    -> Van van = (Van)c : c앞에 Van형으로 형변환한다.

 

  Note) 실행 결과

  - Car가 참조하는 변수가 원래 Van이기 때문에 형변환이 가능하다. 

  - 실제로 생성된 것이 Van이었기 때문에 Van으로 타입을 바꿀 수 있다. 

  

 

07-42.3 클래스 형변환 실습

 

  Ex 1) Car클래스는 gas라는 필드를 가진다. Car클래스를 상속받은 Suv, Track, Bus 클래스가 있다. 

GasStation 클래스에서는 fill(주유하다)라는 메서드가 있다. 총 3종류의 fill 메서드가 오버로딩되어 있다. 각각 Car, Suv, Track, Bus 클래스를 한번씩 살피고 GasStation코드를 살핀 후 결과를 확인하라.

 

<hide/>
package javaStudy;
public class Suv extends Car {
	public Suv(String name) {
		super.name = name;
	}		
}
<hide/>
package javaStudy;
public class Truck extends Car {
	public Truck(String name) {
		super.name = name;
	}
}
<hide/>
package javaStudy;
public class Bus extends Car {	
	public Bus(String name) {
		super.name = name;
	}
}
<hide/>
package javaStudy;
public class Car{
	public int gas;
	public String name;
}
<hide/>
package javaStudy;
public class GasStation {
	public static void main(String[] args) {
		GasStation gasStation  = new GasStation();
		Suv suv = new Suv("suv");
		Truck truck = new Truck("Truck");
		Bus bus = new Bus("Bus");
		
		gasStation.fill(suv);
		gasStation.fill(truck);
		gasStation.fill(bus);
	}
	public void fill(Car car) {
		System.out.println( car.name + "에 기름을 넣습니다." );
		car.gas += 10;
		System.out.println("기름이 " + car.gas + "리터 들어있습니다." );
	}
}

  Note) 출력 결과

  - public void fill(Car car) : 메서드의 매개변수로 Car 타입만 들어가야 한다. 

  - 그런데 실제 사용하는 코드를 보면 fill(suv)처럼 Suv타입도 들어가고

  - Car타입이 아닌데도 해당 메서드를 에러 없이 사용한다. 

  - Suv, Truck, Bus 타입이 Car타입으로 형변환 돼서 fill 메서드를 실행한다. 

  - 하위타입을 상위타입으로 형변환 하면 묵시적 형변환이 일어난다.

  - fill메서드에 인자로 Car의 하위 클래스들이 들어가면 해당 메서드 안에서 사용될 때

  - Car타입으로 형변환이 일어난 상태이므로 하위 클래스에서 추가로 정의한 부분에는 접근할 수 없다.  

 

 

07-42.4 클래스 형변환 실습

 

  Ex 2) Car를 상속 받은 Bus클래스에는 announcements 메서드가 있다. 하지만 타입이 Car인 ㄱ경우에는

announcemants 메서드가 있어도 사용할 수 없다. 다음 코드에서 car.announcements();에 에러가 난다. 

에러가 발생하지 않도록 announcements(); 메서드를 사용하도록 코드 수정하라.

<hide/>
package javaStudy;
public class CarExam {
	public static void main(String[] args) {		
		
		Car car = new Bus();
		car.run();
//오답		car.announcements();
		Bus bus = null;
		bus = (Bus) car;
		bus.announcements();
	}
}
<hide/>
package javaStudy;
public class Car{
	public void run() {
		System.out.println("차가 달립니다.");
	}
}
<hide/>
package javaStudy;
public class Bus extends Car {
	public void announcements() {
		System.out.println("안내방송을 합니다.");
	}
}

   Note) 출력 결과

  - Car를 상속받은 Bus클래스에는 announcaments() 메서드가 있다. 

  - 하지만 타입이 Car형이므로 announcaments() 메서드를 사용할 수 없다. 

  - 따라서 car.announcaments(); 에서 오류가 발생한다.

  - 부모 타입으로 자식 타입을 사용할 수는 있으나 타입이 부모 타입일 경우에 자식이 추가로 정의한 메서드에 접근할 수 없다. 

  - 이 때 메서드를 사용하기 위해 Car타입을 Bus 타입으로 형변환 해야한다. 

  - 하위 타입을 상위 타입으로 형변환 할 때는 묵시적 형변화 일어난다.

  - 상위 차입을 하위 타입으로 형변환 하는 경우에는 반드시 명시적 형변환을 해줘야한다.