📌 자동 타입 변환(promotion)
자동적으로 타입 변환이 일어나는 것
자식은 부모의 특징과 기능을 상속 => 부모와 동일하게 취급 가능
바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 promotion 가능
부모타입 변수 = 자식타입객체; //자식타입을 부모타입으로 promotion
📌 promotion의 참조
Cat cat = new Cat(); //cat Cat 참조
Animal animal = cat; //animal Cat 참조
📌 promotion의 메소드
promotion 이후, 부모 클래스에 선언된 필드와 메소드만 접근 가능
자식 객체를 참조하지만 변수로 접근은 promotion된 클래스의 메소드만 가능
자식 클래스에서 오버라이딩된 메소드가 있다면 오버라이딩된 메소드 호출 => 다형성
class Parent {
void method1() {...}
void method2() {...}
}
class Child extends Parent {
void method2() {...} //오버라이딩
void method3() {...}
}
class ChildExample {
public static void main(String[] args) {
Child child = new Child();
Parent parent = child; //promotion
parent.method1(); //호출 가능
parent.method2(); //오버라이딩된 Child의 method2 실행
parent.method3(); //호출 불가능
}
}
📌 강제 타입 변환 (casting)
부모 타입을 자식 타입으로 강제 타입 변환
자식 객체가 부모 타입으로 자동 변환된 후 다시 자식 타입으로 변환할 때만 가능
부모 타입으로 promotion 후, 원래의 자식 타입에 선언된 필드와 메소드를 꼭 사용할 때 casting
자식타입 변수 = (자식타입) 부모타입객체; //원래 자식타입이었던 부모타입을 다시 자식타입으로 casting
📌 다형성
사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질
객체 사용 방법이 동일하다 == 동일한 메소드를 가지고 있다
자동 타입 변환, 메소드 재정의(오버라이딩)로 구현
(예시) 메소드는 동일하지만 오버라이딩된 내용이 달라 다른 결과가 나옴
📌 필드 다형성
필드 타입은 동일하지만, 대입되는 객체가 달라져 실행 결과가 다양하게 나오는 것
클래스의 타입 변환 후, 오버라이딩 된 메소드를 사용하면 타입 변환에 따라 실행 결과가 달라짐 => 다형성
public class Car {
public Tire tire;
public void run() {
tire.roll();
}
}
Car mycar = new Car();
myCar.tire = new ATire();
myCar.tire = new BTire();
myCar.run(); //ATire와 BTire에 오버라이딩된 메소드에 따라 run()의 결과값이 달라짐
📌 매개변수 다형성
메소드가 클래스 타입의 매개변수를 가지고 있을 경우, 매개변수에 자식 객체를 제공할 때 다형성 발생
자동 타입 변환으로 인해 매개변수에 자식 객체도 제공 가능
어떤 자식 객체가 제공되느냐에 따라 메소드의 실행 결과가 달라짐 => 매개변수의 다형성
public calss Driver {
public void drive(Vehicle vehicle) {
vehicle.run() //매개변수에 따라 run()의 실행결과가 달라짐(bus.run(), vehicle.run()...)
}
}
//Bus는 Vehicle의 자식 클래스일 때,
Driver driver = new Driver();
Bus bus = new Bus();
driver.drive(bus); //자동 타입 변환 발생 Vehicle vehicle = bus;
📌 instanceof
변수가 참조하는 객체의 타입을 확인
instanceof의 앞의 객체의 타입이 instanceof 뒤의 타입과 같다면 true, 다르다면 false
타입 변환을 해도 동일한 객체를 참조한다는 점을 이용해서 로직 구현 가능 (promotion의 참조 부분 확인)
boolean result = 객체 instanceof 타입;
📌 instanceof 활용
강제 타입 변환을 할 수 있는지 확인하기 위해 사용
casting은 자식 타입이 부모 타입으로 promotion된 후 사용 가능
promotion 후에도 동일한 객체를 참조 (자식 타입의 객체 참조)
따라서, instanceof로 참조된 객체를 확인해 강제 타입 변환이 가능한지 확인 가능
public void method(Parent parent) {
if (parent instanceof Child) {
Child child = (Child) parent; //참조가 자식 타입이라면 casting 가능
}
}
📌 instanceof 활용 (java 12~)
instanceof 연산이 true일 경우, 우측 타입 변수 사용 가능
강제 타입 변환 필요 없음
public void method(Parent parent) {
if (parent instanceof Child child) {
//child 변수 바로 사용 가능
}
}
📌 실체 클래스
📌 추상 클래스
실체 클래스 ==(상속)==> 추상 클래스
실체 클래스들의 공통적인 필드나 메소드를 추출해 선언한 클래스
실체 클래스의 부모 역할
실체 클래스는 추상 클래스를 상속해 공통적인 필드나 메소드 물려받을 수 있음
new 연산자로 객체 직접 생성 불가, 새로운 실체 클래스를 만들기 위한 부모 클래스로만 사용
extends 뒤에만 올 수 있음
//Parent는 abstract로 추상 클래스 선언된 상태
Parent paret = new Parent(); //불가
class Child extends Parent {
...
}
📌 추상 클래스 선언
abstract 키워드
new 연산자를 통한 직접 객체 생성 불가, 상속을 통해 자식 클래스 생성만 가능
필드, 생성자, 메소드 선언 가능
자식 클래스에서 super()로 추상 클래스 생성자 호출
public abstract class 클래스명 {
//필드
//생성자
//메소드
}
📌 추상 메소드와 재정의
추상 클래스 작성 시, 메소드 선언부(리턴타입, 메소드명, 매개변수)만 동일하고 실행 내용은 자식 클래스마다 달라야 할 경우 => 추상 메소드 사용
메소드 앞에 abstract 키워드
메소드 실행 내용인 중괄호 {} 없음
공통 메소드라는 것만 정의하고 실행 내용을 가지지 않음
자식 클래스에서 반드시 재정의(오버라이딩)해서 실행 내용을 채워야 함
abstract 리턴타입 메소드명(매개변수, ...);
public abstract class Parent {
//메소드 선언
public void method1() {
...
}
//추상 메소드 선언
public abstract void method2();
}
public class Child extends Parent {
//추상 메소드 재정의
@Override
public void method2() {
...
}
}
📌 봉인된 클래스(sealed class)
Java 15 이후 사용 가능
무분별한 자식 클래스 생성 방지
permits 키워드로 상속 가능한 자식 클래스를 지정해 다른 클래스는 상속 불가능하게 막음
상속 받은 클래스들은 final, non-sealed, sealed 키워드 필요
final : 상속 받은 클래스 이후로 더 이상 상속 불가하게 막기
non-sealed : 상속 받은 클래스 이후로 상속 가능
sealed : 상속 받은 클래스 이후로 정해진 클래스만 상속 가능
//permits 뒤의 클래스들만 상속 가능
public sealed class 부모클래스 permits 자식클래스1, 자식클래스2, ... { ... }
public final class 자식클래스1 extends 부모클래스 { ... } //자식클래스1은 다른 클래스에 상속 불가
public non-sealed class 자식클래스2 extends 부모클래스 { ... } //자식클래스2는 다른 클래스에 상속 가능