SKSDUD

[객체지향 프로그래밍 심화] (3) 다형성 본문

CodeStates/Section 01

[객체지향 프로그래밍 심화] (3) 다형성

NYinJP 2023. 2. 8. 00:19

캡.상.추.다

생각정리

가.

인스턴스를 생성해야 클래스가 의미가 있다. 설계도만으로는 소비자에게 도움 되지 않는다. TV 객체가 있어야 한다.

new 연산자로 인스턴스를 생성하는 것이다. new 키워드 뒤에 나오는 생성자로 인스턴스 변수들을 초기화한다. 

클래스명 변수명  // 클래스 객체를 참조하기 위한 참조변수를 선언. 
변수명 = new 클래스명( ) // 클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장

 

참조 타입은 객체의 번지를 참조하는 타입으로 기본형 타입 8가지를 제외한 나머지로 배열, 열거, 클래스, 인터페이스 타입이 있다. 참조 변수에는 메모리상의 주소값이 위치하고 그 주소값을 통해 객체를 참조한다는 의미로 참조 타입이라 부른다. 클래스도 참조 타입이 될 수 있다. 이 부분에서 어려움을 느끼는 것 같다.

클래스가.. 참조타입이 된다면..? 그 참조변수는 어떻게 되는 걸까..?

인스턴스를 생성할 때 클래스의 객체를 참조하기 위해 참조변수를 클래스타입으로 선언하였다. 

그리고 new 키워드로 인스턴스를 생성한 후 이 인스턴스의 주소를 참조변수에 저장하였다. 

 

그저 클래스형 정보를 담고 있다는 의미에서 클래스형 참조타입을 쓰는걸까? 다시 고민.. 

 

나. 

UML 다이어그램이 상속을 표현하는 방식이다. 

자식 클래스 ➡ 부모 클래스

기능의 확장이라서 화살표가 아래로 향할 것 같지만 그 반대이다.

자식은 부모를 바라보며 큰다

라는 말로 외우면 될거같다. 

 

 

다. 오버라이딩

조상 클래스로부터 상속 받은 내용을 변경하는 것이 오버라이딩이다.

주의점은 메서드 시그니처부분이 조상 클래스에서 구현했던 것과 동일해야 하며 { } 블록 안의 내용만 재정의 한 것이다.

 

예) Object 클래스의 toString메서드 오버라이딩 

    @Override
    // 오버라이딩 : 오버라이딩은 메서드 시그니처가 일치해야한다. 블록 안의 내용만 재정의
    public String toString() {return "computer";}

 

1. 개요

다형성(Polymorphism)

Poly : 여러 개
Morphism : 실체
하나의 객체가 여러 가지 형태를 가질 수 있는 성질

 

지금까지 생성된 인스턴스를 다루기 위해서, 

인스턴스의 타입과 일치하는 타입의 참조변수만을 사용했다. 

Tv tv = new Tv( );
SmartTv smartTv = new SmartTv( );

Tv t = new SmartTv()  // 조상 타입의 참조변수로 자손 인스턴스를 참조

이처럼 인스턴스의 타입과 참조변수의 타입이 일치하는 것이 보통이지만, Tv 와 SmartTv와 같이

클래스가 서로 상속관계에 있을 경우 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조하도록 하는 것이 가능하다.

 

SmartTv클래스의 인스턴스를 참조변수 t가 참조하고 있더라도 t는 SmartTv인스턴스의 멤버 중에서 Tv 클래스의 멤버들만 사용가능하다. 자손타입의 참조변수로 조상 클래스의 인스턴스를 참조하는 것은 가능할까?? 그렇지 않다. 실제 인스턴스인 Tv의 멤버보다 smartTv타입의 참조변수가 쓸 수 있는 멤버가 더 많기 때문이다. 

 

 

조상타입의 참조변수로 자손 타입의 인스턴스를 참조할 수 있다.

자손타입의 참조변수로 조상 타입의 인스턴스를 참조할 수는 없다. 

 

    public static void main(String[] args){
        Friend friend = new Friend(); //같은 타입
        BoyFriend boyFriend = new BoyFriend(); //같은 타입
        Friend girlFriend = new GirlFriend(); // 참조변수의 타입과 인스턴스의 타입이 다르다!

        friend.friendInfo();
        boyFriend.friendInfo();
        girlFriend.friendInfo();

    }

 

2. 참조변수의 형변환

기본형의 형변환 처럼 참조변수도 형변환이 가능하다. 단, 서로 상속관계에 있는 클래스 사이에서만 가능하다

조상타입의 참조변수를 자손타입으로(업캐스팅/형변환 연산자 생략 가능)
자식타입의 참조변수를 조상타입으로(다운캐스팅/ 형변환 연산자 생략 불가)
public class VehicleTest {
    public static void main(String[] args){
        Car car = new Car();
        Vehicle vehicle = (Vehicle) car;
        Car car2=(Car) vehicle;
//        MotorBike motorBike = (MotorBike) car; //에러!
    }
}

사용할 수 있는 멤버변수의 개수를 조절하기 위해 사용한다.  

 

형변환을 위한 조건

1. 서로 상속관계에 있어야 한다. 

2. 자식에서 조상으로의 타입변환은 형변환 연산자(괄호) 생략 가능하다.

3. 조상에서 자식으로의 타입변환은 형변환 연산자를 반드시 명시해야 한다.

  • 3번과 같은 다운캐스팅은 업캐스팅이 되어있는 참조변수에 한해서만 가능하다.

 

 

instanceof 연산자

instanceof 연산자는 앞서 배웠던 참조변수의 타입 변환, 즉 캐스팅이 가능한 지 여부를 booelan 타입으로 확인할 수 있습니다. 캐스팅 가능 여부를 판단하기 위해서는 

 

해당 객체를 어떤 생성자로 만들었니?

클래스 사이에 상속관계가 존재하니?

 

를 판단해야 하는데 이는 어렵다. instanceof 연산자를 통해 쉽게 알 수 있다. 주로 조건문에 사용되며, 어떤 타입에 대한 instanceof 검사가 true이면 그 타입으로 형변환을 할 수 있다는 의미입니다. 

참조_변수 instanceof 타입

void doWork(Car c){
  if( c instanceof FireEngine){ // true라면
    FireEngine fe = (FireEngine) c; // 형변환 수행
    fe.water();
  }
}

다형적 표현 방법을 지원합니다. 

 

 

 

느낀 점

  • 이상한 부분에 꽂혀서 헤매고 있는 걸까?라는 생각이 들었다. 
  • 개념은 light 하게 계속 반복