군만두의 IT 공부 일지

[스터디4] 03. 상속 본문

프로그래밍/Java

[스터디4] 03. 상속

mandus 2025. 2. 9. 22:42

목차

     

    이번에는 7장 상속에 대해서 정리하려고 합니다. 상속은 프로젝트에서 다양하게 사용되기 때문에 확실히 알아두는 게 좋을 것 같습니다.

    7장. 상속

    7.7 타입 변환

    • 타입 변환: 타입을 다른 타입으로 변환하는 것
      • 클래스의 타입 변환은 상속 관계에 있는 클래스 사이에서 발생함.

    자동 타입 변환

    • 자동 타입 변환(Promotion): 자동적으로 타입 변환이 일어나는 것
      • 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능함.
      • 변수는 자식 객체를 참조하지만, 변수로 접근 가능한 멤버는 부모 클래스 멤버로 한정됨.
      • 자식 클래스에서 오버라이딩된 메소드가 있다면, 부모 메소드 대신 오버라이딩된 메소드가 호출됨.
    // 자동 타입 변환 조건
    부모타입 변수 = 자식타입객체;
    Cat cat = new Cat();
    Animal animal = cat;
    
    또는
    
    Animal animal = new Cat();

    cat과 animal 변수는 타입만 다를 뿐, 동일한 Cat 객체를 참조한다. 따라서 두 참조 변수의 == 연산 결과는 true가 나온다.

    강제 타입 변환

    • 강제 타입 변환(Casting): 자식 타입은 부모 타입으로 자동 변환되지만, 부모 타입은 자식 타입으로 자동 변환되지 않아 캐스팅 연산자로 강제로 타입을 변환하는 것
      • 자식 객체가 부모 타입으로 자동 변환된 후 다시 자식 타입으로 변환할 때 사용할 수 있음.
      • 자식 객체가 부모 타입으로 자동 변환하면 부모 타입에 선언된 필드와 메소드만 사용 가능함. 자식 타입에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 자식 타입으로 변환해야 함.
    // 강제 타입 변환 조건
    자식 타입 변수 = (자식타입) 부모타입객체;
    Parent parent = new Child();	// 자동 타입 변환
    Child child = (Child) parent;	// 강제 타입 변환

    7.8 다형성

    • 다형성: 사용 방법은 동일하지만 실행 결과가 다양하게 나오는 성질
      • 다형성을 구현하기 위해서 자동 타입 변환메소드 재정의가 필요함.

    필드 다형성

    • 필드 다형성: 필드 타입(사용 방법)은 동일하지만, 대입되는 객체가 달라져서 실행 결과가 다양하게 나올 수 있는 것
    // Tire.java
    package ch07.sec08.exam01;
    
    public class Tire {
        // 메소드 선언
        public void roll() {
            System.out.println("회전합니다.");
        }
    }
    
    // HankookTire.java
    package ch07.sec08.exam01;
    
    public class HankookTire extends Tire {
        // 메소드 재정의(오버라이딩)
        @Override
        public void roll() {
            System.out.println("한국 타이어가 회전합니다.");
        }
    }
    
    // KumhoTire.java
    package ch07.sec08.exam01;
    
    public class KumhoTire extends Tire {
        // 메소드 재정의(오버라이딩)
        @Override
        public void roll() {
            System.out.println("금호 타이어가 회전합니다.");
        }
    }
    
    // Car.java
    package ch07.sec08.exam01;
    
    public class Car {
        // 필드 선언
        public Tire tire;
    
        // 메소드 선언
        public void run() {
            // Tire 필드에 대입된 객체의 roll() 메소드 호출
            tire.roll();
        }
    }
    
    // CarExample.java
    package ch07.sec08.exam01;
    
    public class CarExample {
        public static void main(String[] args) {
            // Car 객체 생성
            Car myCar = new Car();
    
            // Tire 객체 장착
            myCar.tire = new Tire();
            myCar.run();
    
            // HankookTire 객체 장착
            myCar.tire = new HankookTire();
            myCar.run();
    
            // KumhoTire 객체 장착
            myCar.tire = new KumhoTire();
            myCar.run();
        }
    }

    Car 클래스의 run() 메소드는 tire 필드에 대입된 객체의 roll() 메소드를 호출한다. HankookTire와 KumboTire가 roll() 메소드를 재정의하고 있기 때문에 재정의된 roll() 메소드가 호출된다.

     

    이처럼 어떤 타이어를 장착했는지에 따라 roll() 메소드의 실행 결과가 달라지는 것이 필드의 다형성이다.

    매개변수 다형성

    다형성은 필드보다는 메소드를 호출할 때 많이 발생한다. 메소드가 클래스 타입의 매개변수를 가지고 있을 경우, 호출할 때 동일한 타입의 객체나 자식 객체를 제공하면서 다형성이 발생한다.

    // Driver.java
    public class Driver {
        public void drive(Vehicle vehicle) {
            vehicle.run();
        }
    }
    
    // Drive 메소드 호출 예시
    Driver driver = new Driver();
    Vehicle vehicle = new Vehicle();
    driver.drive(vehicle);

    Driver 클래스에 Vehicle 매개변수를 갖는 drive() 메소드가 정의되어 있다. drive() 메소드는 매개값으로 전달받은 vehiclerun() 메소드를 호출하는데, 자동 타입 변환으로 Vehicle의 자식 객체도 제공할 수 있다. 만약 자식 객체가 run() 메소드를 재정의하고 있다면 재정의된 run() 메소드가 호출된다.

     

    이처럼 어떤 자식 객체가 제공되느냐에 따라서 drive()의 실행 결과가 달라지는 것이 매개변수의 다형성이다.

    7.9 객체 타입 확인

    변수가 참조하는 객체의 타입을 확인하고자 할 때 instanceof 연산자를 사용한다.

    boolean result = 객체 instanceof 타입;
    if(parend instanceof Child child) {
    	// child 변수 사용
    }

    위 코드에서는 Child 타입으로 강제 타입 변환하기 전에 매개값이 Child 타입인지 여부를 instanceof 연산자로 확인한다. Java 12부터는 instanceof 연산의 결과가 true일 경우, 우측 타입 변수를 사용할 수 있어 강제 타입 변환이 필요 없다.

    7.10 추상 클래스

    • 실체 클래스: 객체를 생성할 수 있는 클래스
    • 추상 클래스: 실체 클래스들의 공통적인 필드나 메소드를 추출해서 선언한 클래스
    • 추상 클래스는 새로운 실체 클래스를 만들기 위한 부모 클래스로만 사용됨.

    Bird, Insect, Fish와 같은 실체 클래스에서 공통되는 필드와 메소드를 따로 선언한 Animal 클래스를 만들 수 있다. 또한, Animal 클래스를 상속해서 실체 클래스를 만들 수 있다.

    추상 클래스 선언

    클래스 선언에 abstract 키워드를 붙이면 추상 클래스 선언이 된다. 추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 new 연산자를 사용해서 객체를 직접 생성할 수 없고, 상속을 통해 자식 클래스만 만들 수 있다. 그리고 자식 객체가 생성될 때 super()로 추상 클래스의 생성자가 호출되기 때문에 생성자가 있어야 한다.

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

    추상 메소드와 재정의 

    추상 클래스를 작성할 때 메소드 선언부(리턴타입, 메소드명, 매개변수)만 동일하고 실행 내용은 자식 클래스마다 달라야 하는 경우가 많다. 이런 경우를 위해서 추상 클래스는 abstract 키워드가 붙고 메소드 실행 내용인 {}가 없는 추상 메소드를 선언할 수 있다. 추상 메소드는 자식 클래스에서 반드시 재정의(오버라이딩)해서 실행 내용을 채워야 한다.

    abstract 리턴타입 메소드명(매개변수, ...);
    public abstract class Animal {
    	abstract void sound();
    }

    7.11 봉인된 클래스

    기본적으로 final 클래스를 제외한 모든 클래스는 부모 클래스가 될 수 있다. Java 15부터 무분별한 자식 클래스 생성을 방지하기 위해 봉인된(sealed) 클래스가 도입되었다.

     

    sealed 키워드를 사용하면 permits 키워드 뒤에 상속 가능한 자식 클래스를 지정해야 한다. 봉인된 클래스를 상속하는 자식 클래스는 final 또는 non-sealed 키워드로 상속 가능 여부를 선언하거나, sealed 키워드를 사용해서 봉인 클래스로 선언해야 한다.

    public sealed class Person permits Employee, Manager { ... }

     Person은 자식 클래스로 Employee와 Magager만 될 수 있는 봉인된 클래스이다.

    public final class Employee extends Person { ... }
    public non-sealdd class Manager extends Person { ... }

    Employee는 더 이상 자식 클래스를 만들 수 없지만 Manager는 자식 클래스를 만들 수 있다.

     

    이 글은 『이것이 자바다』 책을 학습한 내용을 정리한 것입니다.

    '프로그래밍 > Java' 카테고리의 다른 글

    [스터디4] 06. 제네릭  (0) 2025.03.02
    [스터디4] 05. 중첩 선언과 익명 객체  (0) 2025.02.25
    [스터디4] 04. 인터페이스  (1) 2025.02.16
    [스터디4] 02. 클래스  (0) 2025.01.31
    [스터디4] 01. 참조 타입  (0) 2025.01.23
    Comments