◇ 다형성
- 참조 변수의 타입 변환
- 자동 타입 변환 : 부모 타입 변수 = 자식 타입 객체; 상황에서는 자동으로 부모 타입으로 형변환이 발생
ex) Whale클래스는 Mammal클래스를 상속받는다고 할 때
※ swimming()메서드는 Whale클래스에만 있는 메서드
public class Main { public static void main(String[] args) { // 고래는 포유류이기 때문에 포유류 타입으로 변환될 수 있습니다. Mammal mammal = new Whale(); // 즉, 부모 클래스에 swimming이 선언되어있지 않아서 사용 불가능합니다. mammal.swimming(); // 오류 발생 // 즉, 부모타입의 객체는 자식타입의 변수로 변환될 수 없습니다. Whale whale = new Mammal(); // 오류 발생 mammal.feeding(); } }
- 강제 타입 변환 : 위 코드에서 mammal.swimming() 메서드를 사용하려면 자동 형 변환 된 객체를 강제 변환 필요
※ 자식 타입 객체가 부모 타입으로 자동 타입 변환 된 객체만 가능Mammal mammal = new Whale(); Whale whale = (Whale) mammal; whale.swimming();
※ 부모 타입 변수로는 자식 타입 객체의 고유한 멤버를 사용할 수 없기 때문에 강제 형변환 필요
Mammal newMammal = new Mammal(); Whale newWhale = (Whale) newMammal; // ClassCastException 발생
- 자동 타입 변환 : 부모 타입 변수 = 자식 타입 객체; 상황에서는 자동으로 부모 타입으로 형변환이 발생
◇ instance of
다형성 기능으로 인해 해당 클래스 객체의 원래 클래스명을 체크하는 것
'대상객체' instance of '클래스 이름' 으로 사용 boolean값 출력
class Parent { }
class Child extends Parent { }
public class Main {
public static void main(String[] args) {
Parent pc = new Child(); // 다형성 허용 (자식 -> 부모)
Parent p = new Parent();
Parent c = new Child();
System.out.println(p instanceof Object); // true 출력
System.out.println(p instanceof Parent); // true 출력
System.out.println(p instanceof Child); // false 출력
System.out.println(c instanceof Object); // true 출력
System.out.println(c instanceof Parent); // true 출력
System.out.println(c instanceof Child); // true 출력
}
}
◇ 추상 클래스
미완성된 설계도, abstract를 통해 선언
public abstract class 추상클래스명 {
abstract 리턴타입 메서드이름(매개변수, ...);
}
※ 상속받은 클래스에서 추상 클래스의 추상 메서드는 반드시 오버라이딩 되어야 한다.
public class Main {
public static void main(String[] args) {
Car car1 = new BenzCar();
car1.horn();
Car car2 = new AudiCar();
car2.horn();
Car car3 = new ZenesisCar();
car3.horn();
}
}
public class c1 {
public method1() {}
public method2() {}
public method3-c1() {}
}
public class c2 {
public method1() {}
public method2() {}
public method3-c2() {}
}
public class c3 {
public method1() {}
public method2() {}
public method3-c3() {}
}
위와같이 각 클래스에 method1, method2가 완전 일치하고 method3만 클래스별로 다르다면
public abstract class Car {
public method1() {}
public method2() {}
public abstract method3();
}
public class c1 extends Car {
@Override
public method3() {재정의}
}
public class c2 extends Car {
@Override
public method3() {재정의}
}
public class c3 extends Car {
@Override
public method3() {재정의}
}
- 각 클래스의 공통된 메서드를 묶어 Car class(부모 클래스)에 정의하고 자식 클래스들에게 상속한다.
- 자식 클래스들은 추상화된 메서드만 오버라이딩하여 각 클래스마다 재정의해준다.
◇ 인터페이스
두 객체를 연결해주는 다리 역할
- 인터페이스 구성
- 모든 멤버 변수는 public, static, final이어야 한다.(생략가능)
- 모든 메서드는 public, abstract이어야 한다.(생략가능)
- 인터페이스 구현
- ※ 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 한다 만약,
인터페이스의 추상 메서드의 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경해주면된다. public class 클래스명 implements 인터페이스명 { // 추상 메서드 오버라이딩 @Override public 리턴타입 메서드이름(매개변수, ...) { // 실행문 } }
- ※ 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 한다 만약,
- 인터페이스 상속
- 인터페이스 간의 상속은 extands 키워드를 사용한다.
- 인터페이스는 클래스와 다르게 다중 상속이 가능하다.
public class Main extends D implements C {
@Override
public void a() {
System.out.println("A");
}
@Override
public void b() {
System.out.println("B");
}
@Override
void d() {
super.d();
}
public static void main(String[] args) {
Main main = new Main();
main.a();
main.b();
main.d();
}
}
interface A {
void a();
}
interface B {
void b();
}
interface C extends A, B {
}
class D {
void d() {
System.out.println("D");
}
}
◇ 디폴트 메서드와 static 메서드
- 디폴트 메서드 : 추상 메서드의 기본적인 구현을 제공하는 메서드
- 메서드 앞에 default 키둬으를 붙인다.
- 접근 제어자가 public이며 생략가능하다.
- static 메서드 : 인터페이스에서 static 메서드 선언이 가능
- static의 특성 그대로 인터페이스의 satic 메서드 또한 객체 없이 호출이 가능
public class Main implements A {
@Override
public void a() {
System.out.println("A");
}
public static void main(String[] args) {
Main main = new Main();
main.a();
main.aa();
System.out.println();
// static 메서드 aaa() 호출
A.aaa();
}
}
interface A {
void a();
default void aa() {
System.out.println("AA");
}
static void aaa() {
System.out.println("static method");
}
}