[Java] 상속

박채은·2022년 11월 7일
0

Java

목록 보기
13/30

학습 목표

  • 상위 클래스-하위 클래스의 상속 관계의 핵심을 이해하고, 그 장점을 설명할 수 있다.
  • extends 키워드를 사용하여 두 개 이상의 클래스 간 상속 관계를 정의할 수 있다.
  • 포함관계와 상속관계의 차이를 설명할 수 있다.
  • 상속 관계에서 사용할 수 있는 메서드 오버라이딩의 정의, 성립 조건, 장점을 이해하고 이를 활용할 수 있다.
  • supersuper() 의 차이를 설명할 수 있다.
  • Object 클래스가 자바 클래스의 상속계층도에서 최상단에 위치한다는 사실을 이해할 수 있다.

상속

기존의 클래스를 재활용해서 새로운 클래스를 작성하는 자바의 문법

이때 상속 관계에 있는 두 클래스를 상위 클래스, 하위 클래스라고 말한다.
하위 클래스상위 클래스가 가진 모든 멤버(필드, 메서드, 이너 클래스)를 상속 받는다.
따라서 하위 클래스의 멤버 개수는 상위 클래스보다 많거나 같고, "상위 클래스로부터 확장되었다!" 라는 표현을 쓴다.

특징

  • extends 키워드를 사용

  • 하위 클래스상위 클래스가 가진 모든 멤버(필드, 메서드, 이너 클래스)를 상속 받는다.
    (하지만 상위 클래스의 생성자는 상속되지 않는다.)

  • 하위 클래스의 멤버 개수는 항상 상위 클래스보다 많거나 같다.

  • 단일 상속만을 허용 (다중 상속은 불가!)
    => 하지만 인터페이스를 통해서 다중 상속과 비슷한 효과가 일어나긴 한다.

  • 상위 클래스의 접근 제어가 private이나 default로 설정된 멤버는 하위 클래스에서 상속받지만 접근할 수는 없습니다.


왜 상속을 사용하는가?

  1. 코드를 재사용해서 적은 양의 코드로 새로운 클래스를 작성할 수 있다. => 코드의 중복을 제거
  2. 다형적 표현이 가능하다.
    ex) 사람이라는 객체가, 학생/어린이/노인으로 표현될 수 있다.

다형적 표현이란?
💁‍♀️ 하나의 객체가 여러 모양으로 표현될 수 있다는 것을 다형성이라고 한다.


포함 관계

클래스의 멤버로 다른 클래스의 참조 변수를 선언하는 것
(내부 클래스가 아닌 경우도 O)

public class Employee {
    int id;
    String name;
    Address address;

    public Employee(int id, String name, Address address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    void showInfo() {
        System.out.println(id + " " + name);
        System.out.println(address.city+ " " + address.country);
    }

    public static void main(String[] args) {
        Address address1 = new Address("서울", "한국");
        Address address2 = new Address("도쿄", "일본");

        Employee e = new Employee(1, "김코딩", address1);
        Employee e2 = new Employee(2, "박해커", address2);

        e.showInfo();
        e2.showInfo();
    }
}

class Address {
    String city, country;

    public Address(String city, String country) {
        this.city = city;
        this.country = country;
    }
}

Employee 클래스의 멤버로, Address 클래스의 참조변수가 존재한다.

포함 관계와 상속 관계 구분

  • 상속: ~은 ~이다(IS-A)
  • 포함: ~은 ~을 가지고 있다.(HAS-A)

오버라이딩(Overriding)

상위 클래스로부터 상속받은 메서드를 재정의 하는 것
** Override = "덮어쓰다"

오버라이딩의 조건

  1. 메서드의 선언부(메서드 이름, 매개변수, 반환타입)이 상위클래스의 그것과 완전히 일치해야한다.
  2. 접근 제어자의 범위가 상위 클래스의 메서드보다 같거나 넓어야 한다.
  3. 예외는 상위 클래스의 메서드보다 많이 선언할 수 없다.

(2,3번은 몰랐던 내용이라 추가 학습이 필요할 것 같다!)

왜 오버라이딩을 사용하는가?

상위 클래스로부터 상속받은 메서드를 다른 방식으로 사용하기 위해서

ex) toString()


예제

public class Main {
    public static void main(String[] args) {
        Bike bike = new Bike(); // 각각의 타입으로 선언 + 각각의 타입으로 객체 생성
        Car car = new Car();
        MotorBike motorBike = new MotorBike();
        
	    bike.run();
        car.run();
        motorBike.run();

	    Vehicle bike2 = new Bike(); // 상위 클래스 타입으로 선언 + 각각 타입으로 객체 생성
        Vehicle car2 = new Car();
        Vehicle motorBike2 = new MotorBike();

        bike2.run();
        car2.run();
        motorBike2.run();
    }
}

class Vehicle {
    void run() {
        System.out.println("Vehicle is running");
    }
}

class Bike extends Vehicle {
    void run() {
        System.out.println("Bike is running");
    }
}

class Car extends Vehicle {
    void run() {
        System.out.println("Car is running");
    }
}

class MotorBike extends Vehicle {
    void run() {
        System.out.println("MotorBike is running");
    }
}

// 출력값
Bike is running
Car is running
MotorBike is running

Bike is running
Car is running
MotorBike is running

아래 코드와 같이, 각 하위 클래스 객체를 상위 클래스 타입으로 선언하고 오버라이딩된 메서드를 호출하면 원본 메서드가 아닌, 각 하위 클래스에 재정의된 오버라이딩 메서드들이 호출된다.

Vehicle bike2 = new Bike(); // 상위 클래스 타입으로 선언 + 각각 타입으로 객체 생성
Vehicle car2 = new Car();
Vehicle motorBike2 = new MotorBike();

bike2.run();
car2.run();
motorBike2.run();

// 출력
Bike is running
Car is running
MotorBike is running

그러므로 여러 하위 클래스들의 객체를 모두 상위 클래스타입의 배열로 선언하면, 간편하게 이들을 관리할 수 있다.

Vehicle[] vehicles = new Vehicle[] { new Bike(), new Car(), new MotorBike()};
for (Vehicle vehicle : vehicles) {
		vehicle.run();
}

super/super()

super/super()의 관계는 이전에 배웠던 this/this()의 관계와 비슷하다.

this: 자신의 객체를 가리킴
this(): 자신의 생성자를 호출
super: 상위 클래스의 객체를 가리킴
super(): 상위 클래스의 생성자를 호출

super

public class Main {
    public static void main(String[] args) {
        Lower l = new Lower();
        l.callNum();
    }
}

class Upper {
    int count = 20; // super.count
}

class Lower extends Upper {
    int count = 15; // this.count

    void callNum() {
        System.out.println("count = " + count); // (this.)count
        System.out.println("this.count = " + this.count);
        System.out.println("super.count = " + super.count);
    }
}

// 출력값
count = 15
this.count = 15
super.count = 20

superthis 키워드를 붙이지 않으면, 자신의 속한 인스턴스 객체의 멤버를 먼저 참조한다!


super()

public class Main {
    public static void main(String[] args) {
        Student s = new Student();
    }
}

class Human {
    Human() {
        System.out.println("휴먼 클래스 생성자");
    }
}

class Student extends Human { // Human 클래스로부터 상속
    Student() {    
        super(); // Human 클래스의 생성자 호출
        System.out.println("학생 클래스 생성자");
    }
}
  • super는 반드시 생성자 안에서만 사용 가능하다.
  • 모든 생성자의 첫 줄에는 반드시 this() 또는 super()가 선언되어야 한다.
  • super()가 없는 경우에는, 컴파일러 생성자의 첫 줄에 자동으로 super()를 삽입한다.

클래스를 만들 때는 기본 생성자를 생성하는 것을 꼭 습관화 하자!


Object 클래스

자바의 최상위 클래스
➡️ 모든 클래스는 Object 클래스를 상속받는다.

0개의 댓글