JAVA/이것이 자바다

이것이 자바다 | 7장 상속

한 면만 쓴 종이 2022. 7. 7. 03:16

 

상속 방법: 자식 클래스를 선언할 때 어떤 부모 클래스를 상속받을 것인지를 결정

class 자식클래스 extends 부모클래스 {
    // 필드
    // 생성자
    // 메소드
}

< 예시 >

class SportsCar extends Car {
}

    *자바는 다중 상속을 허용하지 않음 -> extends 뒤에는 하나의 부모 클래스만 와야 함

 

 

7.3 부모 생성자 호출

부모 생성자는 자식 생성자의 맨 첫 줄에서 호출됨

    => 만약 자식 클래스의 생성자가 명시적으로 선언되지 않았다면 컴파일러는 기본 생성자를 생성함

< 기본 생성자 예 >

public 자식클래스() {
    super();
}

super() 은 부모의 기본 생성자를 호출함

 

직접 자식 생성자를 선언하고 명시적으로 부모 생성자를 호출하고 싶은 경우

자식클래스(매개변수선언, ... ) {
    super(매개값, ... );
    ...
}

부모 클래스에 기본 생성자가 없고 매개 변수만 있는 생성자만 있다면 자식 생성자에서 반드시 부모 생성자 호출을 위해 super(매개값, ... ) 을 명시적으로 호출해야 함

 

< 예시 >

// 부모 클래스
public class People {
    public String name;
    public String ssn;
    
    public People(String name, String ssn) {
        this.name - name;
        this.ssn = ssn;
    }
}
// 자식 클래스
public class Student extends People {
    public int studetNo;
    
    public Studnet(String name, String ssn, int studentNo) {
        super(name, ssn);    // 부모 생성자 호출
        this.studentNo = studentNo;
    }
}

 

7.4 메소드 재정의

1. 메소드 오버라이딩

메소드 오버라이딩: 상속된 메소드의 내용이 자식 클래스에 맞지 않을 경우, 자식 클래스에서 동일한 메소드를 재정의하는 것

 

메소드 오버라이딩 시 규칙

  • 부모의 메소드와 동일한 시그니처를 가져야 함
  • 접근 제한을 더 강하게 오버라이딩 할 수 없음
  • 새로운 예외를 throws할 수 없음

1. 부모 메소드 호출(super)

자식 클래스에서 오버라이딩 된 부모 클래스의 메소드를 호출해야 하는 경우, super 키워드로 호출 가능

super.부모메소드();

 

7.5 final 클래스와 final 메소드

1. 상속할 수 없는 final 클래스

클래스 선언 시, final 키워드를 class앞에 붙이면 최종적인 클래스가 되어 상속할 수 없는 클래스가 됨

 

2. 오버라이딩 할 수 없는 final 메소드

메소드 선언 시, final 키워드를 붙이면 최종적인 메소드가 되어 오버라이딩 할 수 없음

=> 자식 클래스에서 재정의 불가

 

7.6 protected 접근 제한자

protected | 접근할 수 없는 클래스: 다른 패키지에 소속된 클래스 ( 자식 클래스 제외 )

필드, 생성자, 메소드 선언에 사용 가능 (클래스 X)

 

A 클래스와 D 클래스가 다른 패키지에 있음

  • A 클래스의 protected 필드, 생성자, 메소드에 접근 가능
  • new 연산자를 사용해서 생성자 직접 호출은 불가
  •     => 자식 생성자(D)에서 super()로 A생성자 호출 가능
import package1.A;

public class D extends A {    // D클래스가 A클래스 상속받음
    public D() {
        super();
        this.field = "value";
        this.method();
    }
}

 

7.7 타입 변환과 다형성

클래스 타입 변환은 상속 관계에 있는 클래스 사이에서 발생

자식 타입은 부모 타입으로 자동 타입 변환 가능

< 예 >

public class Car {
    Tire t1 = new HankookTire();
    Tire t2 = new KumhoTire();
}

 

1. 자동 타입 변환

 

부모 타입으로 자동 타입 변환이 된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능

하지만, 메소드가 자식 클래스에서 오버라이딩 되었다면 자식 클래스의 메소드가 대신 호출됨!

 

2. 필드의 다형성

 

  • Car 클래스에 4개의 Tire 필드가 있음
  • frontRightTire와 backLeftTire를 HankookTire와 KumhoTire로 교체해야 함
Car myCar = new Car();
myCar.frontRightTire = new HankookTire();
myCar.backLeftTire = new KumhoTire();
myCar.run();

frontRightTire와 backLeftTire에는 원래 Tire 객체가 저장되어야 하지만, Tire의 자식 객체가 저장되어도 됨

(자동 타입 변환 됨)

 

3. 하나의 배열로 객체 관리

상속 관계에 있는 객체들을 배열로 관리하면 제어문에서 많은 혜택을 봄

 

4. 매개 변수의 다형성

매개 변수의 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로 사용할 수 있음

 

5. 강제 타입 변환(Casting)

강제 타입 변환: 부모 타입을 자식 타입으로 변환하는 것

◈ 자식 타입이 부모 타입으로 자동 변환한 후, 다시 자식 타입으로 변환할 때 사용 가능!

    => 강제 타입 변환은 자식 타입이 부모 타입으로 변환되어있는 상태에서만 가능

자식클래스 변수 = (자식클래스) 부모클래스타입;

    *부모클래스타입 = 자식 타입이 부모 타입으로 변환된 상태

// 강제 타입 변환 (캐스팅)
Parent parent = new Chile();   // 자동 타입 변환
Child child = (Child) parent;  // 강제 타입 변환

 

6. 객체 타입 확인(instanceof)

 

boolean result = 좌항(객체) instanceof 우항(타입)
// example
if (parent instanceof Child) {
    ...
}

좌항의 객체가 우항의 타입으로 생성되었다면 true, 그렇지 않으면 false 반환

 

 

7.8 추상 클래스

추상: 공통되는 특성

실체 클래스의 멤버를 통일화하는데 목적이 있음

추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 객체를 직접 생성해서 사용할 수 없음

-> new연산자로 생성 불가

=> extends 뒤에만 올 수 있음

class Ant extends Animal { ... }

✓ 추상 클래스의 용도

    1. 실체 클래스들의 공통된 필드와 메소드의 이름 통일 목적

    2. 실체 클래스를 작성할 때 시간 절약

 

1. 추상 클래스 선언

선언에 abstract 키워드를 붙여야 함

public abstract class 클래스 {
    // 필드
    // 생성자
    // 메소드
}

 

2. 추상 메소드와 오버라이딩

추상 메소드: 메소드의 선언부만 있고 메소드의 실행 내용인 중괄호 {} 가 없는 메소드

메소드를 선언만 하고 각 자식 클래스마다 실행하는 내용을 다르게 하고 싶을 때 사용

    => 하위 클래스가 반드시 실행 내용을 채우도록 강요하고 싶은 메소드가 있을 경우 추상 메소드로 선언

            ↪ 자식 클래스는 반드시 추상 메소드를 오버라이딩해서 실행 내용을 작성해야 함

public abstract class Animal {
    public abstract void sound();
}

<  자식 클래스에서 오버라이딩 예 >

public class Dog extends Animal {
    public Dog() {
        this.kind = "포유류";
    }
    
    @Override    // 재정의
    public void sound() {
        System.out.println("멍멍");
    }
}