[Java]상속
상속
상속은 객체 지향 프로그래밍의 핵심 요소 중 하나로, 기존 클래스의 필드와 메서드를 새로운 클래스에서 재사용하게 해준다. 이름 그대로 기존 클래스의 속성과 기능을 그대로 물려받는 것이다. 상속을 사용하려면
extends
키워드를 사용하면 된다. 그리고extends
대상은 하나만 선택 할 수 있다.
- 용어 정리
- 부모 클래스 (슈퍼 클래스) : 상속을 통해 자신의 필드와 메서드를 다른 클래스에 제공하는 클래스
- 자식 클래스 (서브 클래스) : 부모 클래스로부터 필드와 메서드를 상속받는 클래스
상속은 부모의 기능을 자식이 물려 받는 것이다. 따라서 자식이 부모의 기능을 물려 받아서 사용할 수는 있으나, 부모 클래스는 자식 클래스에 접근할 수 없다.
단일 상속 - 자바는 다중 상속을 지원하지 않는다. 다중 상속을 사용하게 되면 부모클래스에 이름이 동일한 메서드가 있을 때 어느쪽의 메서드를 사용해야하는지에 대한 문제가 생긴다.(다이아몬드 문제) 또한 다중 상속을 사용하면 클래스의 계층 구조도가 매우 복잡해질 수 있다. 이런 문제점 때문에 자바는 클래스의 다중 상속을 허용하지 않는다. 대신 인터페이스를 통한 다중 구현을 허용하여 단일 상속으로서 발생할 수 있는 문제점을 해결할 수 있다.
⭐️ 상속과 메모리 구조
위와 같은 상속구조를 가진 클래스가 있다고 가정하자.
New ElectricCar() 생성
new ElectricCar()
를 호출하면 ElectricCar뿐만 아니라 상속 관계에 있는 부모클래스 Car를 포함하여 인스턴스를 생성하게 된다. 참조값은 하나지만, 실제로 그 안에는 Car, ElectricCar라는 두가지 클래스 정보가 공존하는 것이다. 즉, 상속은 단순히 부모의 필드와 메서드만을 물려받는 것이 아니라, 부모 클래스를 함께 포함해서 생성하는 것이다.
electricCar.charge() 호출 (메서드 호출)
electricCar.charge()
를 호출하면 참조값을 확인하여 .charge()를 호출하는데 위와 같이 상속을 받은 경우 내부에 부모와 자식이 모두 전재한다. 이때 부모인 Car의 charge()를 선택할 지, 아니면 자식인 ElectricCar의 charge()를 선택할 지 골라야한다. 이때는 호출하는 변수의 타입(클래스)를 기준으로 선택하게 된다.ElectricCar electricCar = new ElectricCar();
위와 같이 코드를 작성한 경우 호출한 타입 (=반환 타입)이 ElectricCar이므로 인스턴스 내부의 같은 타입인 ElectricCar의 charge()를 호출한다. 만약 ElectricCar에 charge() 메서드가 없었다면, 그 다음 부모 클래스의 charge()를 찾게된다.
상속과 메서드 오버라이딩
부모에게서 상속 받은 기능을 자식이 재정의 하는것을 오버라이딩(Overriding)이라고 한다.
@Override
@
이 붙은 부분을 어노테이션이라 한다. 어노테이션은 주석과 비슷한데, 프로그램이 읽을 수 있는 특별한 주석이라 생각하면 된다. 이 어노테이션은 해당 메서드가 상위 클래스의 메서드를 오버라이드 하는 것임을 나타낸다.
이름 그대로 오버라이딩한 메서드 위에 이 어노테이션을 붙여야한다.
컴파일러는 이 어노테이션을 보고 메서드가 정확히 오버라이드 되었는지 확인된다. 어노테이션을 붙이지 않아도 기능은 동작하지만 어노테이션을 사용하면 오버라이딩 조건을 만족시키지 않은 경우 컴파일 에러를 발생시켜 실수로 오버라이딩을 못하는 경우를 방지해준다.
오버로딩(Overloading)과 오버라이딩(Overriding)
메서드 오버로딩 : 메서드 이름이 같고 매개변수(파라미터)가 다른 메서드를 여러개 정의하는 것을 메서드 오버로딩이라한다.
메서드 오버라이딩 : 하위클래스에서 상위클래스의 메서드를 재정하는 과정을 의미한다. 따라서 상속 관계에서 사용한다.
메서드 오버라이딩 조건
- 메서드 이름이 같아야한다.
- 매개변수(파라미터) 타입, 순서, 개수가 같아야한다.
- 반환 타입이 같아야 한다. 단, 반환 타입이 하위 클래스의 타입일 수 있다.
- 오버라이딩 메서드의 접근 제어자는 상위 클래스의 메서드보다 더 제한적이어서는 안된다.
static
,final
,private
키워드가 붙은 메서드는 오버라이딩 될 수 없다.- 생성자는 오버라이딩 할 수 없다.
super - 부모 참조, 생성자
부모와 자식의 필드명이 같거나 메서드가 오버라이딩 되어 있으면, 자식에서 부모의 필드나 메서드를 호출할 수 없다. 이 때 super
키워드를 사용하면 부모 클래스를 참조할 수 있다.
상속관계의 인스턴스를 생성하면 결국 메모리 내부에는 자식과 부모 클래스가 각각 다 만들어진다.
→ 따라서 각각의 생성자도 모두 호출되야한다.
상속 관계를 사용하면 자식 클래스의 생성자에서 부모 클래스의 생성자를 반드시 호출해야 한다. (규칙)
상속관계에서 부모의 생성자를 호출할때는 .super()를 사용하면 된다. (매개변수가 없는 기본생성자인 경우에는 생략가능)
Step.1 ~ 3
new ClassC()
를 통해ClassC
인스턴스를 생성한다. 이때ClassC()
의 생성자가 먼저 호출되는 것이 맞다. 하지만ClassC()
의 성생자는 가장 먼저super(..)
를 통해ClassB(...)
의 생성자를 호출한다.ClassB()
의생성자도 부모인ClassA()
의 생성자를 가장 먼저 호출한다.Step.4 ~ 6
ClassA()
의 생성자는 최상위 부모이다. 생성자 코드를 실행하면서"ClassA 생성자"
를 출력한다.ClassA()
생성자 호출이 끝나면ClassA()
를 호출한ClassB(...)
생성자로 제어권이 돌아간다.ClassB(...)
생성자가 코드를 실행하면서"ClassB 생성자 a=10 b=20"
를 출력한다. 생성자 호출이 끝나면ClassB(...)
를 호출한ClassC()
의 생성자로 제어권이 돌아간다.ClassC()
가 마지막으로 생성자 코드를 실행하면서"ClassC 생성자"
를 출력한다.
Leave a comment