JAVA/JAVA 국비지원 수업 정리

JAVA 14일차 수업
깝몬 2023. 5. 18. 17:50

부모/자식 클래스간의 타입변환

1.자식클래스 > 부모클래스 (자동 타입변환)

Class GrandFather{
	String name = "김할아버지";
    void dance(){System.out.println("할아버지의 춤 메소드");}
}

Class Father extends GrandFather{
	int age = 55;
    void excercise(){System.out.println("아빠의 운동 메소드");}
}

Class Son extends Father{
	char grade = 'B';
    void study(){System.out.println("아들의 공부 메소드");}
    
}

 

 

이와같이 선언된 부모, 자식클래스들이 있다고 해보자.

여기에 생성자는 선언되어있지 않지만 default 생성자는 이미 우리가 사용할 수 있기때문에 아들클래스 객체를 하나 생성 할 수 있다.

 

이때 아들 클래스의 필드는 grade 하나 뿐인데, 상속받은 클래스이기때문에 

 

Father fa1 = new Son(); // 아들로 만들어져 아빠로 변환! > 성공!
Son so1 = new Father(); // 아빠로 만들어져 아들로 변환! > 실패~

 

 

이와같이 new 를 이용하여 새로운 Son 객체를 생성 후 Father로 Casting 하는데에는 제약이 존재하지 않는다.

그리고 Casting된 객체는 오버라이딩 되기 전의 부모 method와 field를 접근 할 수 있다.

물론 오버라이딩 하지 않는 자식객체의 method도 이용 할 수 있다.

 

그러나 부모의 Class에서 생성된 객체는 자식 객체로 Casting 할수 없게된다.

 

 

 

그렇다면 fa1 이라는 객체는 이제 Father 라는 클래스의 객체인걸까?

 

결론부터 말하면 그렇지 않다

 

fa1는 Father의 클래스에 속해있지만, 태생적으로 Son에서 생성된 객체이기때문에 자신이 원래 Son의 클래스에 속해있다는 사실은 변하지 않는다. 이것을 확인하는 방법은 추후에 다뤄보도록 하겠다.

 

2. 부모클래스 > 자식클래스 (강제 타입변환)

자동 타입변환에서 우리가 배운것은 자식은 상위클래스로 변환하는데 전혀 걸릴것이 없다는 것이다.

 

반대의 경우는 컴파일 에러가 발생하기 때문에 우리가 강제로 타입을 변환해야하는데

 

이때 객체의 태생클래스를 중요하게 살펴보아야한다.

 

 

 

예시를 살펴보자.

 

우선 아들 클래스와 아빠 클래스를 할아버지 클래스로 자동 변환 해보겠다.

GrandFather so2 = new Son();
GrandFather fa2 = new Father();

 

우리는 so2와 fa2가 모두 GrandFather클래스의 객체이지만 각자 태생 클래스가 Son, Father라는 걸 알 수 있다.

 

이것을 이제 강제 형변환 해보겠다.

 

Father faSo2 = (Father) so2; // so2를 Father 클래스로 강제변환 >> 문제 발생!
Father faFa2 = (Father) fa2; // fa2를 Father 클래스로 강제변환 

Son soSo2 = (son)so2; // so2를 Son 클래스로 강제변환
Son soFa2 = (son)fa2; // fa2를 Son 클래스로 강제변환 >> 문제 발생!

 

각자의 태생클래스보다 자식클래스로는 강제변환을 할수 없기때문에 태생이 Father 클래스인 fa2는 Son클래스로 강제 형변환을 시도했을때 에러를 띄우게된다.

 

그러나 so2는 분명히 Son클래스를 참조하여 만들어진 객체인데 왜 Father로 강제변환하면 문제가 발생하는걸까?

 

우리는 자료구조를 지금은 단일 가지구조를 가진 상속구조를 가지고있다.

 

하지만 단일구조가 아닌 다중구조일때를 살펴보자.

 

다중구조가 되었을때 중간클래스로의 강제변환을 허용한다면 생기는 오류의 예시

위와 같은 그림을 보면 처음클래스 객체를 참조하던 상위 클래스의 객체는 중간객체로 자동변환 할 수 있을 경우

 

다른 가지의 클래스로 변형을 하게되면 더이상 처음의 객체를 참조할 수 없는 클래스가 되어 논리상 오류가 생길 수 밖에 없다.

 

그러므로 우리는 강제 형변환은 처음의 참조객체로만 이루어질수 있음을 명심하자!

 

 

 

우리는 이때 각자의 생성자를 살펴보지 않는이상 강제 캐스팅했을때 문제가 생길지 안생길지 알 수 없고, 

 

실제로

이번엔 여자들의 가족으로 부모 자식 클래스를 생성하여 변형해 보았다.

 

 

이러한 식으로 잘못된 강제 변환임에도 불구하고 error를 보이지 않고 컴파일시에만 

 

왜 미리 바꿔달라고 알려주질 않니..

이런식의 오류만 출력한다.

 

이러한 일을 방지하기 위해 우리는 태생클래스를 확인 할 필요가 있다.

 

3. Instanceof 메서드

※미리요약 : 클래스객체의 참조여부에 대하여 boolean 타입으로 응답하는 method

 

문법 >

// (객체) istanceof (클래스 타입)
// 예시
ChoongAng instanceof Academy // ChoongAng 객체는 Academy 클래스의 객체를 참조하는가?

지금까지는 이해를 위해 태생이라는 단어를 사용했다. 

 

하지만 이제는 프로그래밍적 언어로 바꾸어 이야기해보겠다.

GrandFather so2 = new Son();
GrandFather fa2 = new Father();

위의 코드에서 사용했듯 이런식으로 자동타입변환 된것에 대하여

 

so2는 GrandFather클래스이며, Son의 객체를 참조한다.

 

fa2는 GrandFather클래스이며, Father의 객체를 참조한다.

 

 

이것을 instanceof 메서드를 통해 확인해보자.

 

test1 = so2 instanceof Son; // so2객체는 생성할때 Son 클래스 객체를 참조하였으므로 true!
test2 = fa2 instanceof Son; // fa2객체는 생성할때 Father 클래스를 객체를 참조하였으므로 false!

test3 = so2 instanceof Father; 
// 그렇다면 우리의 머릿속에서 so2객체는 생성당시 참조객체인 Son보다 상위인 Father로 자동 변환이 가능하다.
// 이것은 true일까??

 

이 상황에서 제일 헷갈리기 좋은 것은 instanceof 가 강제 타입변환 가능성을 제시하는 것이 아니라는 것이다.

 

test3을 출력해보면 false를 출력하게된다. 

 

instanceof 는 정말 참조객체의 클래스에만 true를 출력하는것이지 변환이 가능하지만 참조한적이 없다면 false를 응답한다. 헷갈리기 좋으니 이에 주의하자.

 

 

변환 여부를 확인했다면 이를 이용하여 예제를 만들어보겠다.

 

GrandFather example1 = new Son();

// example1객체가 Son클래스객체를 참조하여 true일경우 바꾸고, 그렇지 않다면 바꾸지않는다.
if(example1 instanceof Son){
	System.out.println("변환 가능!")
    example1Success = (Son)example1;
}else{
	System.out.println("변환할 수 없습니다.")
}
// 방금 배운 내용에 따르면 당연히 성공!

// example1객체가 Father클래스객체를 참조하여 true일경우 바꾸고, 그렇지 않다면 바꾸지않는다.
if(example1 instanceof Father){
 	System.out.println("변환 가능!")
	example2Success = (Father)example01;
}else{
	System.out.println("변환할 수 없습니다.")
}
//분명히 강제 형변환은 자식,부모객체의 상하구조에 따르면 가능하다.
//그런데 이것은 false를 출력하여 "변환할 수 없습니다"를 내놓는다.

 

 

위의 내용을 잘 보면 instanceof가 정확히 무엇을 하는지 이해할 수 있을 것이다.

 

사실 강제 형변환에 대하여 잘 이해했다면 instanceof의 역할이 명확하게 인지될 것이다.

 

 

 

다형성(Polymorphism)

상속성을 이용하여 부모클래스의 field를 argument로 받는 parameter 의 자리에 자식 클래스의 field에 argument또한 사용 될수 있는 것을 우리가 parameter의 다형성 이라고 부른다.

 

예시를 들어보자 

 

class Driver{		//vehicle을 parameter로 받는 method를 실행할 Class Driver 생성
	void drive(Vehicle vehicle) {
		vehicle.run();
	}
}


class Vehicle{ 		//부모객체가 될 Vehicle 을 생성 
	void run() {System.out.println("vehicle 달려요");}
}

class Car extends Vehicle{ 	// Vehicle을 상속한 Car Class
	void run() {System.out.println("car 달려요");}
}

class Bus extends Vehicle{	// Vehicle을 상속한 Bus Class
	void run() {System.out.println("bus 달려요");}
}

public class Polymorphism {
	public static void main(String[] args) {
		Driver driver = new Driver();
		Bus bus = new Bus();
		driver.drive(bus); 	// 분명 Driver 클래스의 겍체 메서드 drive는 parameter를 vehicle로 명시했지만
    						// 상속된 Class인 bus의 객체를 arguments로 사용해도 문제가 없다.
		Car car = new Car();
        driver.drive(car);	//위의 논리와 동일하게 drive 메서드의 argument로 vehicle의 자식인
        }					// car객체를 사용해도 된다!
}

 

상속관계가 있어서 Overrindg이 있기때문에 같은 메서드를 다른 객체가 받아 실행하면 다른 내용물을 출력하게 됨을 볼 수 있다.

 

 

인터페이스

인터페이스의 문법

public interface Example{
	public void run();
}

인터페이스는 클래스와는 다른 영역으로 Abstract라는 가장 큰 특징을 가진다.

 

Abstract의 성질로 인해 생성자를 갖지 않으머, method 또한 Abstract의 성질로 구현부인 {   } 을 갖지 않는다. 따라서 인터페이스 만으로는 무엇을 해야할지 정해지지 않는다.

 

그로인하여 인터페이스를 구현하는 클래스는 인터페이스의 method를 구현해주어야만 한다. 구현하지 않을시 에러를 일으킨다!

 

 

 

 

★인터페이스에 대하여 다음시간에 더 자세히 알아봅시다.

'JAVA > JAVA 국비지원 수업 정리' 카테고리의 다른 글

JAVA 17일차 수업  (0) 2023.05.24
JAVA 15일차 수업  (0) 2023.05.19
JAVA 12일차 수업  (0) 2023.05.16
JAVA 11일차 수업  (0) 2023.05.15
JAVA 10일차 수업  (0) 2023.05.11