일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 인터페이스의역할
- 인스턴스메소드
- map에서key와value
- 자동타입변환
- 람다식
- 생성자참조
- 구현클래스
- 디폴트메소드
- 객체타입확인
- 배열을 문자열
- find
- 공백 처리
- 자바
- ZipInputStream
- 필드의다형성
- 상속
- 선택한요소
- 인터페이스
- 익명구현객체
- 정적메소드
- jQuery
- 요소
- 상수필드
- java
- createTempFile
- 문자열을 배열
- 추상메소드
- 매개변수참조
- 타깃타입
- 오버라이딩
- Today
- Total
코드지우개
다형성과 상속 본문
다형성
다형성이란?
- 같은 이름의 메소드가 클래스 혹은 객체에 따라 다르게 동작하도록 구현되는 것
- 실제 동작은 다르더라도 개념적으로 동일한 작업을 하는 메소드에 똑같은 이름을 부여하여 코드의 중복을 줄일 수 있다.
- 오버라이딩( Overriding )과 오버로딩( Overloading )이 대표적인 예
- 효과 : 객체를 부품화시킬 수 있다. (예 : 자동차 타이어)
오버라이딩( Overriding )
오버라이딩( Overriding )이란?
자바에서는 메소드 오버라이딩을 통해 상속받은 부모 클래스의 메소드를 자식 클래스에서 직접 재정의할 수 있다.
오버라이딩의 조건
1. 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 리스트)를 가져야 한다.
오버라이딩은 메소드의 동작만을 재정의하는 것이므로, 메소드의 선언 부는 기존 메소드와 완전히 같아야 한다. 하지만 메소드의 반환 타입은 부모 클래스의 반환 타입으로 타입 변환할 수 있는 타입이라면 변경할 수 있다.
2. 접근 제한을 더 강하게 오버라이딩할 수 없다.
public을 default나 private으로 수정할 수 없다. 반대로 default는 public으로 수정할 수 있다.
3. 새로운 예외(Exception)을 throws 할 수 없다.
오버라이딩한 메소드의 예외는 오버라이딩 된 부모 클래스의 메소드에 선언된 예외가 아닌 새로운 예외를 선언할 수 없다.
public class Parent {
public void method1() { ... }
public void method2() { ... }
}
public class Child extends Parent{
public void method2() { ... } //재정의( @Override )
public void method3() { ... }
}
public static void main(String[] args) {
Child child = new Child();
child.method1();
child.method2(); //재정의된 메소드 호출
child.method3();
}
오버로딩( Overloading )
오버로딩( Overloading )이란?
같은 이름의 메소드를 중복하여 정의하는 것을 의미한다.
오버로딩의 조건
1.메소드의 이름이 같아야 한다.
2. 메소드의 시그너처, 즉 매개변수의 개수 또는 타입이 달라야 한다.
(메소드 오버로딩은 반환 타입과는 관계가 없다. 만약 메소드의 시그니처는 같은데 반환 타입만이 다른 경우에는 오버로딩이 성립하지 않는다.)
public class Parent {
public void method1(String a, String b) {
System.out.println(a + "," + b);
}
public void method1(String a, String b, String c) {
System.out.println(a + "," + b + "," + c );
}
public static void main(String[] args) {
Parent parent = new Parent();
parent.method1("엄마","아빠"); //출력 : 엄마,아빠
parent.method1("엄마","아빠","형"); //출력 : 엄마,아빠,형
}
}
타입 변환과 다형성
다형성은 위에 적어 둔 것처럼 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다.
자바는 다형성을 위해 부모 클래스로 타입 변환을 허용한다. 즉 부모 타입에 모든 자식 객체가 대입될 수 있다.
타입변환이란?
데이터 타입을 다른 데이터 타입으로 변환하는 행위를 말한다. 클래스 타입의 변환은 상속 관계에 있는 클래스 사이에서 발생한다. 자식 타입은 부모 타입으로 자동 타입 변환이 가능하다.
자동 타입 변환( Promotion )

자동 타입 변환이란?
- 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다.
- 자동 타입 변환은 작은 크기를 가지는 타입이 큰 크기를 가지는 타입에 저장될 때 발생한다.
- 타입 변환일 때 자동 타입 변환의 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다.
public class Animal{...}
public class Cat extends Animal{...} // Animal 상속
public static void main(String[] args) {
Cat cat = new Cat();
Animal animal = cat; // 또는 Animal animal = new Cat();
System.out.println(cat = animal) //출력 : true
}
위 코드로 생성되는 메모리 상태를 그림으로 묘사하면 아래와 같다. cat과 animal 변수는 타입만 다를 뿐, 동일한 Cat 객체를 참조한다.
그 예로 == 비교 연산을 해보면 true가 나오는데 참조 변수의 == 비교 연산은 참조 주솟값이 같을 경우 true를 산출하므로 두 변수가 동일한 객체를 참조하고 있다는 뜻 된다.

바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환이 일어날 수 있다.

부모 타입으로 자동 타입 변환된 이후에는 부모 클래스가 선언된 필드와 메소드만 접근이 가능하다. 비록 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정된다. 그러나 예외가 있는데, 메소드가 자식 클래스에서 오버라이딩되었다면 자식 클래스의 메소드가 대신 호출된다.
class Parent{
void method1(){ ... }
void method2(){ ... }
}
class Cild extends Parent{
void method2(){ ... } //parent 재정의 (Overriding)
void method3(){ ... }
}
public static void main(String[] args){
Parent parent = new Child(); //자동 타입 변환
parent.method1(); //가능
parent.method2(); // 재정의된 메소드 호출
parent.method3(); // 호출 불가능 error
필드의 다형성
그렇다면 왜 자동 타입 변환이 필요할까? 자식 타입으로 사용하면 될 것을 부모 타입으로 변환해서 사용하는 이유가 무엇일까?
그것은 다형성을 구현하는 기술적 방법이기 때문이다. ( 부모 타입으로 자동 변환, 재정의된 메소드 Overriding )자동차를 구성하는 부품은 언제든지 교체할 수 있듯이 프로그램도 수많은 객체들이 서로 연결되고 각자의 역할을 하게 되는데, 이 객체들을 다른 객체로 교체될 수 있어야 한다.
예를 들어 자동차에 타이어를 생각해 보자. 자동차를 처음 설계할 때 사용한 타이어는 언제든지 성능이 좋은 다른 타이어 객체로 교체할 수 있어야 한다.

매개 변수의 다형성
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생한다.
메소드를 호출할 때에는 매개 변수의 타입과 동일한 매개값을 지정하는 것이 정석이지만, 매개값을 다양화하기 위해 매개 변수에 자식 타입 객체를 지정할 수도 있다.
public class Parent { //부모
public void run() {
System.out.println("부모가 TV를 켰다.");
}
}
public class Child extends Parent{ //자식
@Override
public void run(){
System.out.println("자식이 TV를 켰다."); //재정의
}
}
public class WatchTv {
public void remote( Parent parent ){
parent.run(); //실행
}
}
위에 코드를 보면 부모 클래스에 run() 메소드가 정의되어 있고 자식 클래스에는 부모를 상속받아 run() 메소드를 재정의(Override)를 하고 있다.
WatchTv 클래스에서는 remote() 메소드가 실행되면 매개변수로 받은 객체에 run() 메소드를 실행하게 되어있다.
여기서 정상적으로 호출한다면 아래와 같다.
WatchTv watchTv = new WatchTv();
Parent parent = new Parent();
watchTv.remote(parent); //출력 : "부모가 TV를 켰다."
WatchTv와 Parent에 객체를 생성해 WatchTv에 remote() 메소드를 호출했을 때 결과는 부모에 run() 메소드가 실행이 될 것이다.
그런데 만약 자식 클래스는 Child 객체를 remote() 메소드의 매개값으로 넘겨준다면 어떻게 될까?
WatchTv watchTv = new WatchTv();
Parent parent = new Parent();
watchTv.remote(parent); //출력 : "부모가 TV를 켰다." (정상적 호출)
Child child = new Child();
watchTv.remote(child); //출력 : "자식이 TV를 켰다." (자동 타입 변환) *재정의 호출
remote() 메소드는 Parent 타입을 매개 변수로 선언했지만, Parent를 상속받은 Child 객체가 매개 값으로 사용되면 자동 타입 변환이 일어난다. 그리고 여기서 Child 클래스에서 재정의한 run() 메소드가 실행이 된다.
즉, 매개 변수의 타입이 클래스일 경우, 해당 클래스의 객체 뿐만 아니라 자식 객체까지도 매개 값을 사용할 수 있다는 것이다. 매개 값으로 어떤 자식 객체가 제공되느냐에 따라 메소드의 실행 결과는 다양해질 수 있다.
강제 타입 변환( Casting )
강제 타입 변환이란?
- 강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말한다.
- 그렇다고 해서 모든 부모 타입을 자식 클래스 타입으로 강제 변환할 수 있는 것은 아니다.
- 자식 타입이 부모 타입으로 자동 변환한 후, 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있다.
강제 타입 변환이 필요한 이유?
자식 타입이 부모 타입으로 자동 변환하면, 부모 타입에 선언된 필드와 메소드만 사용 가능하다는 제약 사항이 따른다. 만약 자식 타입에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 다시 자식 타입으로 변환한 다음 자식 타입의 필드와 메소드를 사용하면 된다.


객체 타입 확인 ( instanceof )
강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 부모 타입의 변수가 부모 객체를 참조할 경우 자식 타입으로 변환할 수 없다.
그렇다면 부모 변수가 참조하는 객체가 부모 객체인지 자식 객체인지 확인을 해야 하는데 이때 instanceof 연산자를 사용하면 된다.
instanceof 연산자의 좌항은 객체가 오고, 우항은 타입이 오는데 좌 항의 객체가 우항의 인스턴스이면 즉, 우항의 타입으로 객체가 생성되었다면 true를 그렇지 않으면 false를 산출한다.

instanceof 연산자는 매개값의 타입을 조사할 때 주로 사용된다. 메소드 내에서 강제 타입 변환이 필요할 경우 반드시 매개값이 어떤 객체인지 instanceof 연산자로 확인하고 안전하게 강제 타입 변환을 해야 한다.
( 매개값으로 어떤 객체가 들어왔는지 실행전까지 확인할 수 없기 때문에 instanceof를 사용한다. )

만약 타입을 확인하지 않고 강제 타입 변환을 시도한다면 ClassCastException 예외가 발생할 수 있다.
'java' 카테고리의 다른 글
인터페이스 ② (0) | 2023.04.13 |
---|---|
추상 클래스 (0) | 2023.03.30 |
HashMap에서 Key, Value 꺼내기 (0) | 2023.03.10 |
contains(), indexof() (0) | 2023.03.07 |
split() : 문자열 -> 배열, join() : 배열 -> 문자열 (0) | 2023.03.07 |