본문 바로가기
JAVA

다형성(polymorphism)과 참조변수의 형변환

by 꿀꿀이냐옹이 2011. 3. 25.
반응형

기초지식

클래스타입 참조변수명=new 클래스타입();

 

이라고 선언한다 하면,

new 클래스타입() <--이 부분은, 해당하는 클래스의 인스턴스를 생성하고,

클래스타입 참조변수명 <--이 부분은, 해당하는 클래스타입의 형식대로 값을 참조하는 참조변수를 만든다. 여기서 형식이란,

주로 해당하는 클래스에 정의된 멤버만 호출할 수 있는 성질을 뜻한다.

 

다형성

상속과 다형성은 OOP의 중요한 특징이다.

객체지향개념에서 다형성이란 '여러 가지 형태를 가질 수 있는 능력'을 뜻한다, 자바에서는 이것을, 한 클래스타입의 참조변수로,

한 클래스타입의 인스턴스를 참조할 수 있게 함으로써, 다형성을 구현하였다.1

 

정확히 말하자면, 한 타입의 참조변수가 아무 조건 없이 모든 타입의 인스턴스를 참조할 수 있는 것은 아닌고, 조상클래스 타입의

참조변수로 자손클래스의 인스턴스 만 참조할 수 있는 것이다.

 

왜냐하면,

클래스타입 참조변수명  <-으로 선언된 참조변수는, 해당하는 클래스타입에 정의된 멤버만 호출할 수 있는데, 만약 이

참조변수명에 전혀 상관없는 클래스타입의 인스턴스를 연결 할 경우, 참조변수를 통해서 인스턴스를 실질적으로 전혀

사용하지 못한다. 하지만 자손클래스의 인스턴스를 참조할 경우, 자손클래스는 조상클래스의 멤버를 상속받기에, 참조변수를

통해서 일부 멤버들을 제어 가능하다.

 

그리고 만약 자손클래스에, 조상클래스에 없는 새로운 멤버를 추가하고, 조상클래스 타입으로 선언된 참조변수를 자손클래스

인스턴스에 연결할 경우, 참조변수를 통해서 인스턴스의 있는 새로 멤버를 호출할 수 없다. 당연하지만, 위 기초지식에도

썼듯이, 참조변수의 타입은 참조변수를 통해 사용할 수 있는 멤버를 정한 것이기 때문에, 비록 인스턴스에는

멤버가 더 있더라도, 참조변수 타입이 그 멤버를 모른다면, 사용할 수 없다.

 

)

class car

start();

stop();

 

class f1 extends car

turbo();

 

car myCar=(car)new f1();

 

이라면, myCar참조변수의 타입이 car이기 때문에, myCarmyCar.start()myCar.stop() 만 호출할 수 있다,

비록 인스턴스는 자손클래스인 f1타입이지만, turbo()myCar가 전혀 알지 못하는 멤버일 뿐이다.

myCar.turbo()  <-turbo()메소드는 존재하지만, myCarturbo()를 모른다.

 

만약 자손클래스 타입의 참조변수가, 조상클래스 인스턴스를 참조할 경우 어떻게 되나?

 

'클래스는 상속을 통해서 확장될 수는 있어도 축소될 수는 없다, 즉 자손클래스의 멤버 개수는 조상클래스의 멤버 개수보다 항상

같거나 많다.'

 

에 따라, 자손클래스 타입의 참조변수는, 실제로 조상클래스 인스턴스의 있는 멤버들 보다 더 많이 안다.

고로 참조변수를 통해서 인스턴스에 전혀 존재하지 않는 멤버에 접근할 수가 있기 때문에, 자바는 이러한 참조를 허용하지 않는다.

 

참조변수의 형변환

 

int a=3;

float b=4.0;

b=a;    //ba보다 더욱 넓은 범위를 수용할 수 있기 때문에, a앞에 굳이 (float)를 붙일 필요 없다.

작은 범위 --> 넓은 범위 (생략 가능)

 

int a=3;

float b=4.0;

a=(int)b;  //반대로 b는 수용할 수 있는 범위를 앞에 (int)를 붙여 축소한 뒤, a에 할당한다.

넓은 범위 --> 작은 범위 (생략 불가)

 

참조변수의 형 변화도 위의 기본형 변수의 형 변환과 맥락을 같이하지만, 개념상 반대되는 부분도 있다.

 

car myCar=new car();

f1 myF1=new f1();

 

myCar=myF1;  //myF1myCar가 수용할 수 있는 조상클래스 + 자손클래스멤버를 알고 있기 때문에, myCar에 굳이

                              (car)를 안 붙여도, 알아서 myCar가 수용할 수 있는 멤버들만 수용한다.

넓은 범위 --> 작은 범위 (생략 가능)

 

 car myCar=new car();

f1 myF1=new f1();

myF1=(f1)myCar //반대로 myCarmyF1보다 수용할 수 있는 멤버 수가 적기에, 앞에 (f1)를 붙여줘야 형

                                  변환을 하여, myF1이 충분히 모든 멤버를  수용할 수 있다.

작은 범위 --> 넓은 범위 (생략 불가)

 

 

사실 참조변수든 기본변수든, 타입이 다른 두 변수에 = 연산자를 사용한다면, 무조건 형 변환이 일어나는 건 맞다, 단지

큰 범위에서->작은 범위로 갈 때나 작은 범위에서->큰 범위로 갈 때 둘 중에 한 경우를 생략할 뿐이다.

 

고로 헷갈린다면

 

b=(float)a;

a=(int)b; 

myCar=(car)myF1;

myF1=(f1)myCar ;

 

와 같이  두 경우 모두 다 앞에 해당하는 타입을 써줘도 무방하다.

 

그리고 기본형 변수의 형 변환에 경우, 형 변환에 결과 때문에 실제적인 변숫값이 변경되어 할당되지만,

참조변수의 형 변환은, 단지 참조변수의 타입을 변환하는 거지, 참조하는 인스턴스에는 아무런 영향을 안 준다.

즉 그저 참조변수가 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.2

 

참조변수의 형 변환에서 주의해야 할 점은,

형 변환은 단지 참조변수 타입간의 변환이므로, 실제로 참조변수가 어떠한 인스턴스를 참조하고 있는지는

고려 안 한다, 고로 조상인스턴스를 참조하고 있는 참조변수를, 자손클래스 타입의 참조변수에 형 변환하여 대입할 경우,

참조변수만 알고, 인스턴스에는 없는 멤버를 호출하는 상황이 생길 수도 있으니프로그램 실행 시 에러가 발생한다.

 

car myCar=new car();

f1 myF1=(f1)myCar;

 

컴파일은 성공하지만, 실행 시 에러 발생.

반응형

'JAVA' 카테고리의 다른 글

JAVA  (0) 2022.08.19
스레드  (0) 2011.08.10
static 사용법  (0) 2011.03.25
추상클래스(abstract class), 추상메서드(abstract method)  (0) 2011.03.25
인터페이스란?  (0) 2011.03.25

댓글