: 상속은 객체 지향 프로그래밍의 핵심요소
기존 클래스의 필드와 메서드를 새로운 클래스에서 재사용할 수 있도록 해준다!
→ 기존 클래스의 속성과 기능을 그대로 물려받는 것.(공통 기능이 있을 때 효과적으로 사용 가능)
✨ extends 키워드 사용
1️⃣ 부모 클래스 (= 슈퍼 클래스)
상속을 통해 자신의 필드 & 메서드를 다른 클래스에 제공
2️⃣ 자식 클래스 (= 서브 클래스)
부모 클래스로부터 상속 받는 클래스
Car 클래스를 만들어서 상속을 이해해보자.
public class Car {
public void move(){
System.out.println("장롱면허 운전 나간다. 나 엑셀 밟는다.");
}
}
Car클래스를 상속해서 ElecCar(전기차 클래스)도 만들자
public class ElecCar extends Car {
public void chargeElec(){
System.out.println("나 전기차. 전기로 충전중");
}
}
Car클래스를 또 상속해서 GasCar(가스차 클래스)도 만들자
public class GasCar extends Car {
public void chargeGas(){
System.out.println("가스차에는 가스를 넣어야지");
}
}
이렇게하면 GasCar, ElecCar가 모두 Car클래스의 move를 사용할 수 있게된다.
이 클래스들을 활용하면,
public class CarMain {
public static void main(String[] args) {
ElecCar elecCar = new ElecCar();
elecCar.move();
elecCar.chargeElec();
GasCar gasCar = new GasCar();
gasCar.move();
gasCar.chargeGas();
}
}
//출력 결과
장롱면허 운전 나간다. 나 엑셀 밟는다.
나 전기차. 전기로 충전중가스차에는 가스를 넣어야지
장롱면허 운전 나간다. 나 엑셀 밟는다.
가스차에는 가스를 넣어야지
이렇게 각각 move() 메서드를 정의하지 않았는데도 각각 클래스에서 move() 메서드를 출력한 것을 확인할 수 있따.~!!
위의 예제와 같이 상속 구조를 만들면, 아래 그림처럼 상속 관계가 만들어진다.

그리고 ElecCar를 호출하면, ElecCar 내부의 charge() 인스턴스만 생성하는 것이 아니라, 상속한 Car클래스의 move()인스턴스까지 포함해서 생성된다.

또한 인스턴스를 호출하면 그 인스턴스가 어떤 클래스에 위치하고 있는지(부모인지 자식인지) 찾아야하는데, 이때 호출한 클래스!! 먼저 탐색하고 만약 거기에 없으면 부모 타입에서 찾는다.
1️⃣ 상속은 부모의 기능을 자식이 물려받는것
(부모는 자식의 클래스에 접근 불가능하다.)
2️⃣ JAVA는 단일 상속만 지원한다! (다중 상속 안됨)
→ 다중 상속을 사용하면 클래스 계층 구조가 매우 복잡해질 수 있기 때문
3️⃣ 상속 관계의 객체를 생성하면, 그 내부에는 부모와 자식이 모두 생성
4️⃣ 객체 호출할 때, 호출한 객체부터 타입을 찾고, 만약 없으면 부모 타입으로 가서 기능을 찾는다.
@Override재정의를 하지 않아도 돼서 상속이 편리하지만, 어떤 자식 타입에서는 다르게 재정의 하고 싶을 때가 있다.
그럴때는 부모에게서 상속 받은 기능을 자식이 재정의하는 Overriding을 활용하면 된다!
Car 클래스를 상속한 ElecCar클래스를 참고해서 오버라이딩해보자.
public class ElecCar extends Car {
public void chargeElec(){
System.out.println("나 전기차. 전기로 충전중");
}
}
이 ElecCar 클래스에서 move() 인스턴스를 좀 다르게 쓰고 싶다면,
@Override 를 사용해서 재정의 할 수 있다.
@ : 애노테이션(프로그램이 읽을 수 있는 특별한 주석)
→ 오버라이딩한 메서드 위에 애노테이션을 붙여준다.
public class ElecCar extends Car {
public void chargeElec(){
System.out.println("나 전기차. 전기로 충전중");
}
//오버라이딩해보자
@Override
public void move(){
System.out.println("ElecCar is faster than the ordinary Car");
}
}
이렇게하면 elecCar.move()를 호출했을 때, 오버라이딩한 메서드가 실행되는 것을 확인할 수 있다!
super 키워드를 사용하는 경우
1. 부모와 자식의 필드명이 같을 때
2. 메서드가 오버라이딩 되어 있을 때
→ 자식에서 부모의 필드나 메서드를 호출할 수 없다.
이때 ✨super✨ 키워드를 사용하면 부모를 참조할 수 있다!!
예시로 알아보자
Parent 클래스와 그를 상속한 Child 클래스, 그리고 Main 클래스를 만들자
//Parent
public class Parent {
public String value = "parent";
public void hello(){
System.out.println("Parent Hello");
}
}
//Child
public class Child extends Parent { //Parent 상속
public String value = "child";//value 재정의
@Override //오버라이딩
public void hello(){
System.out.println("Child.hello");
}
public void call(){//call함수 정의
System.out.println(this.value);
System.out.println(super.value);
this.hello(); //생성자
super.hello();//super
}
}
Child 클래스에서는 this와 super를 통해 각각 hello()함수를 불러오는 모습을 확인할 수 있다.
//메인 클래스
public class super1Main {
public static void main(String[] args) {
Child child = new Child();
child.call();
}
}
실행 결과를 보자

이렇게 오버라이딩을 한 경우에도 super를 사용해서 부모 클래스의 hello 메소드를 불러온 것을 확인할 수 있다!