상속

kailyn·2024년 8월 27일

JAVA

목록 보기
7/17

1. 상속 개요

1. 상속의 정의 및 사용 이유

1-1. 상속(Inheritance)이란?

💡 부모 클래스(생성자 제외)가 가지는 **멤버(필드, 메소드)를 자식 클래스가 물려 받아** 자신의 멤버인 것처럼 사용할 수 있도록 만든 기술이다.(단, 생성자는 물려 받지 않음) 멤버 외에도 **부모 클래스의 타입 또한 상속**이 된다.(다형성의 토대) 자바는 **단일상속**(자식 클래스는 하나의 부모 클래스만 가지는)만 지원한다.

  • 자식 클래스가 부모 클래스를 상속받기 위해서는 extends 키워드를 사용한다.
public class Academy extends Company {

}

1-2. 상속을 사용하는 이유

💡 기존에 작성 된 클래스의 멤버를 **재사용**할 수 있다. 클래스 간 계층 관계를 형성하여 **다형성 문법의 토대**가 된다.
  • 상속을 필요한 순간에 잘 사용하면 유지보수에도 도움이 되지만 무분별하게 사용하면 되려 계층 구조 파악 및 정상 동작을 예측하기 힘들어 유지보수에 되려 어려움을 초래할 수 있다.

  • 부모 클래스와 자식 클래스의 관계에 대해 알아볼 수 있는 실습

    // 부모 클래스와 부모 클래스에게 상속 받은 자식 클래스의 코드에 대한 출력
    
    public class Application1 {
        public static void main(String[] args) {
    
            /* 수업목표. 상속에 대해 이해할 수 있다. */
            /* 필기.
             *  상속은 부모의 멤버를 물려받아 재사용성에 유리하게 만들기 위한 객체지향의 특징이자 문법이다.
             *  하지만 단순히 물려받아 재사용하는 개념보다 부모클래스의 개념을 확장(extends)하는데 더 의의가 있으며
             *  현재 가장 중요한 의미는 '다향성을 적용하기 위한 문법적 토대'가 된다는 사실이다.
             *
             * 필기.
             *  상속의 이점
             *   1. 새로운 클래스를 작성할 시 기존에 작성한 클래스를 재사용할 수 있다.
             *      1-1. 재사용시 생산성을 크게 향상시킬 수 있다.(생산성 측면)
             *      1-2. 부모 클래스만 수정해도 자식 클래스들 전체에 적용된다.(유지보수 측면)
             *   2. 클래스 간의 계층 관계가 형성되며 다형성의 문법적인 토대가 된다.
             *
             * 필기.
             *  상속의 단점
             *   1. 부모 클래스의 기능을 추가/변경할 시 자식 클래스가 정상적으로 작동하게 될지 예측이 힘들다.
             *      (경우에 따라 유지보수에 악영향을 미칠 수 있다.)
             *   2. 부모 클래스에서는 의미 있고 중요했던 기능이 자식 클래스에서는 무의미할 수 있다.
             *      (불필요한 멤버가 추가되기 때문)
             *
             * 필기.
             *  메소드 오버라이딩이란?
             *   메소드를 재정의(Overriding) 하는 것으로 부모 메소드의 헤드부를 그대로 사용하면서 자식 클래스가
             *   정의한 메소드대로 동작하도록 메소드 바디부(몸체)를 새롭게 다시 작성하는 것이다.
             *   이후 다형성을 적용하면 자식의 오버라이딩 된 메소드가 우선적으로 동작하게 된다.(동적 바인딩)
             *
             * 필기.
             *   장점과 단점을 고려했을 때, 상속은 오용의 가능성이 있기 때문에 IS-A 관계로 구분되는 경우에 잘 고려하여 적용해야 한다.
             *   (IS-A 관계 VS HAS-A 관계)
            * */
    
            Car car = new Car();
    
            car.soundHorn();
            car.run();
            car.soundHorn();
            car.stop();
            car.soundHorn();
    
            FireCar fireCar = new FireCar();
    
            fireCar.soundHorn();
            fireCar.run();
            fireCar.soundHorn();
            fireCar.stop();
            fireCar.soundHorn();
            fireCar.sprayWater();
    
            RacingCar racingCar = new RacingCar();
            racingCar.run();
            racingCar.soundHorn();
    
        }
    }
    
    // 부모 클래스
    public class Car {
    
        /* 설명. 자동차의 속성과 기능을 나열 */
        private  boolean runningStatus;
    
        public Car() {                  // extend시 기본 생성자 제외
    				super();                    // 모든 클래스는 object를 따라감
            System.out.println("Car 클래스의 기본 생성자 호출됨...");
        }
    
        public void  run() {
            runningStatus = true;
            System.out.println("자동차가 달리기 시작합니다.");
        }
    
        public void  soundHorn() {
            if(isRunning()) {
                System.out.println("빵~ 빵~");
            } else {
                System.out.println("주행중이 아닐 때는 경적을 울릴 수 없습니다.");
            }
        }
    
        public  boolean isRunning() {
            return runningStatus;
        }
    
        public void stop() {
            runningStatus =false;
            System.out.println("자동차가 멈춥니다.");
        }
    }
    // 자식 클래스
    public class FireCar extends Car{
    
        public FireCar() {            // 자식 클래스가 출력될 때 부모 클래스의 코드가 먼저 돌아야 하기 때문에
            super();                  // super는 부모의 기본 생성자를 뜻함
    				System.out.println("FireCar 클래스의 기본 생성자 호출됨...");
        }
    }
    // 자식 클래스
    
    public class RacingCar extends Car{
    
        @Override
        public void run() {
            super.run();
            System.out.println("레이싱 자동차가 신나게 달립니다. 쌔앵애앵");
        }
    
        @Override
        public void soundHorn() {
            System.out.println("레이싱카는 경적따위 울리지 않습니다.");
        }
    }
    • 결과

      자식 클래스가 부모 클래스를 상속 받아 실행해도 부모 클래스에 있는 기본 상속자가 호출됨


2. 상속의 키워드

1. IS-A

💡 “자식 클래스를 (하나의)부모 클래스이다.”라는 말을 만족(성립)하는 관계를 뜻하며 클래스 간 상속 관계를 파악하기 위한 키워드이다.
  • Circle is a Shape
    은 하나의 모양이다.

2. HAS-A

💡 포함관계를 의미하고 다른 클래스의 기능(변수 혹은 메소드)을 받아들여 사용 특정기능을 사용하고 싶을 때 자주 사용

3. super와 super()

💡 인스턴스 생성 시 부모 생성자를 호출하여 부모 클래스의 인스턴스도 함께 생성하게 되는데, 이 때 생성한 부모 인스턴스의 주소를 보관하는 레퍼런스 변수로 자식 클래스 내의 모든 생성자와 메소드 내에서 묵시적으로 사용할 수 있는 레퍼런스 변수이다.
@Override
public String getInformation() {

	return super.getInformation()
			+ "Computer ["
			+ "cpu=" + this.cpu
			+ ", hdd=" + this.hdd
			+ ", ram=" + this.ram
			+ ", operationSystem=" + this.operationSystem
			+ "]";
}
💡 super()는 부모 생성자를 호출하는 구문으로 인자와 매개변수의 타입, 갯수, 순서가 일치하는 부모의 생성자를 호출하게 된다. super()는 부모 클래스가 가지는 private 생성자를 제외한 나머지 생성자를 호출할 수 있도록 한 구문이다.
public Computer(String cpu, int hdd, int ram, String operationSystem) {
		
		/* 부모클래스의 기본생성자 호출 */
		super();
		
		this.cpu = cpu;
		this.hdd = hdd;
		this.ram = ram;
		this.operationSystem = operationSystem;
}

4. 오버라이딩(Overriding)

💡 부모클래스에서 상속받은 메소드를 **자식 클래스가 재정의**하여 사용하기 위한 기술
  • 오버라이딩 성립 조건
    1. 메소드명 동일
    2. 메소드 리턴타입 동일
    3. 매개변수의 타입, 개수, 순서가 동일
    4. 부모 클래스의 private 메소드는 오버라이딩 불가능
    5. 부모 클래스의 final 키워드가 사용된 메소드는 오버라이딩 불가능
    6. 접근제어자는 부모 메소드와 같거나 더 넓은 범위여야 함
    7. 예외처리는 같은 예외이거나 더 구체적(하위)인 예외를 처리해야 함

  • protected: 다른 클래스들은 안되는데 내 자식 클래스는 가능해!

5. 오버라이딩과 오버로딩

profile
나는 할 수 있다...!

0개의 댓글