본문 바로가기

Java/information

[자바/JAVA] 다형성

다형성: 여러가지 형태를 가질 수 있는 성질


-객체 사용 방법은 동일하지만 실행결과가 다양하게 나오는 성질로 한 번의 코딩으로 여러개의 객체를 생성할 수 있는 원리가 '다형성'이다.
(상속과 같이 불필요한 코드 사용을 줄이는 개념으로 참조변수에 얼마나 다양한 생성자를 받을 수 있는지가 중요하다)
부모 참조 변수에 실제 자식의 인스턴스 참조값을 넣는 것
보이는 참조값은 부모지만, 실제 저장된 값은 자식객체를 가르키는 주소값
상속 관계에서 각 자식 클래스에는 오버라이딩된 메소드를 가지고 있을 때 각각 자식 인스턴스는 자기의 오버라이딩된 메소드를 호출한다.
다형성을 구현하려면 메소드 재정의와 타입 변환이 필요하다 (메소드의 재정의 + 타입 변환 -> 다형성)
타입 변환이랑 타입을 다른 타입으로 변환하는 행위를 말한다. 클래스의 변환은 상속 관계에 있는 클래스 사이에서 발생한다. 자식은 부모타입으로 자동 타입 변환이 가능하다.
자동 타입 변환은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다.
자동 타입 변환의 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다.
예를 들어, 고양이가 동물의 특징과 기능을 상속받았다면 '고양이는 동물이다.'가 성립된다.
바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환이 일어날 수 있다.
부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능하다.
-비록 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정된다. 그러나 예외가 있는데, 메소드가 자식 클래스에서 재정의되었다면 자식 클래스의 메소드가 대신 호출된다.
이것은 다형성과 밀접한 관계가 있기 때문에 매우 중요한 성질이므로 잘 이해하고 알아두어야 한다.!

필드의 다형성
그냥 자식 타입으로 사용하면 될 것을 부모 타입으로 변환해서 사용하는 이유는 다형성을 구현하기 위해서다.
필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 필드 사용 결과가 달라질 수 있다. 이것이 필드의 다형성이다.
예를 들어 자동차를 구성하는 부품은 언제든지 교체할 수 있다. 부품은 고장날 수도 있고, 성능이 더 좋은 부품으로 교체되기도 한다. 객체 지향 프로그래밍도 마찬가지이다.
언제든 성능이 좋은 다른 부품으로 교체하기 하기 위해서는 기존 부품과 사용방법은 동일하지만 실행결과는 더 우수하게 나올수 있게 해야한다.
그것을 프로그램으로 구현하기 위해서는 상속과 재정의, 타입 변환을 이용한다.
자식 클래스는 부모의 메소드를 재정의해서 메소드의 실행 내용을 변경함으로써 더 우수한 실행결과가 나오게 할 수도 있다. 그리고 자식 타입을 부모 타입으로 변환할수도 있다. 이 세가지가 다형성을 구현할 수 있는 기술적 조건이 된다.

다형성의 필수 조건
1)상속 관계
다형성을 활용하기 위해서는 필수로 부모-자식 간 클래스 상속이 이루어져야 한다.
2)오버라이딩 필수(자식 클래스에서 메소드 재정의)
-다형성이 보장되기 위해서는 하위 클래스 메소드가 반드시 재정으되어 있어야 한다.
3)업캐스팅(자식 클래스의 객체가 부모 클래스 타입으로 형변환 되는 것)
-부모 타입으로 자식클래스를 업캐스팅하여 객체를 생성해야 한다.

객체의 부품화: 코드가 어느 한 객체에 종속되지않고 여러 객체를 떼었다 붙였다 할 수 있다. 이 개념은 나중에 인터페이스에서 사용된다.

기본적으로 연관이 없는 다른 클래스끼리는 형변환이 불가능하고 상속 관계에서는 형 변환이 가능한데, 자식 객체를 부모 변수에 넣는 것은 '다형성'이라 하고 자동으로 형변환이 되므로 가에 형 변환이 필요없다. 하지만 부모 객체를 자식 변수에 넣는 것은 강제 형 변환이 꼭 필요하다.
다형성 구현으로 생성자 함수부분만 바꾸면 다양한 형태의 성질을 쉽게 변경 가능하다

instanceof 연산자
어느 인스턴스가 어느 클래스의 인스턴스인지를 판단해야 할 때 사용
인스턴스 instanceof 클래스: 인스턴스가 클래스의 인스턴스라면 true가 됨
객체간의 형 변환시, 상속 관계에서는 자식 객체를 부모 변수에 넣는 '다형성' 구현시 자동 형 변환이 됨
그러나, 부모 객체를 자식 변수에 넣는 것은 형 변환이 꼭 필요하다.

매개변수가 많은경우 클라이언트 측에서 생성자를 호출할 때, 위치에 따라 실수가 일어날 수 있다.
이는 컴파일 오류가 아닌 논리적 흐름에 따른 오류가 발생하여 에러 원인을 찾기가 매우 어려워지는 결과를 야기할 수 있다.
점층적 생성자 패턴(다양한 생성자를 오버로딩)을 사용할 경우 코드가 매우 길어지고 헷갈릴 수 있다.
클라이언트 측은 일일이 매개변수의 개수도 세봐야할 것이고, 어느 곳에 어느 값이 들어가는지도 정확히 확인을 해야한다.
선택 매개변수가 많을 때는 자바빈즈 패턴을 생각해볼 수 있다.

자바빈즈 패턴
디폴트인 매개변수가 없는 생성자 한개만 만든후, getter를 통해 매개변수를 가져오고, setter를 통해 매개변수의 값을 설정하는 방식이다.
자바빈즈의 객체 생성은 반드시 인자값이 없는 기본 생성자가 있어야한다.
자바빈즈 객체의 속성값은 외부에서 직접 접근할 수 없도록 private으로 선언한다. 자바빈즈 개게의 속성값은 메소드로만 접근하게 해야한다.
getter 메소드, setter 메소드를 추가하고 private으로 선언한 멤버변수의 값을 추출하는 getter 메소드와 setter 메소드의 접근자는 누구나 접근이 가능하도록 public으로 선언한다.

클래스 타입 변환: 다른 클래스 타입으로 객체를 대입하는 것을 말한다.
자동 타입 변환: 자식 객체를 부모 타입 변수에 대입할 때에는 자동으로 타입이 변환된다.
강제 타입 변환: 자식 객체가 부모 타입으로 변환된 상태에서 다시 원래의 자식 타입으로 변환하고자 할 때 캐스팅() 연산자를 사용해서 강제 타입 변환할 수 있다.
instanceof 연산자: 객체가 어떤 타입인지 조사할 때 instanceof 연산자를 사용한다. 주로 강제 타입 변환 전에 변환이 가능한지 조사할 때 사용한다.
다형성: 객체 사용 방법은 동일하지만 실행결과가 다양하게 나오는 성질을 말한다. 다형성을 구현하는 기술은 메소드 재정의와 타입 변환이다. 자식 객체가 재정의된 메소드를 가지고 있을 경우, 부모 타입으로 자동 타입 변환 후에 메소드를 호출하면 재정의된 자식 메소드가 호출되면서 다양한 실행결과를 가져올 수 있다.

'Java > information' 카테고리의 다른 글