<정리>
1. 상속이란?
1. 클래스의 상속
상위 클래스(부모 클래스), 하위 클래스(자식 클래스) 라고 한다.
상위 클래스가 하위 클래스보다 일반적인 개념이고 하위 클래스는 상위 클래스보다 구체적인 클래스다.
1) 클래스 문법 상속
상속을 구현할 때는 extends 를 사용한다.
'B 클래스가 A 클래스를 상속받는다'를 코드와 그림으로 나타낸 것이다.
2. 상속을 사용하여 고객 관리 프로그램 구현하기
1) Customer 클래스 구현하기(Customer.java)
모든 멤버 변수를 반드시 private으로 구현할 필요는 없다. 필요에 따라 멤버 변수나 메서드를 외부에 노출하지 않을 목적일 때 private으로 선언하다.
2) VIPCustomer 클래스 구현하기(VIPCustomer.java)
Customer 클래스에 이미 선언된 멤버변수, 메서드는 상속을 받아서 사용하면 되기 때문에 구현할 필요가 없다. 하지만 2가지 문제가 있다.
- customerGrade 변수 오류: 상위 클래스의 customerGrade가 private이므로 외부 클래스(VIPCustomer)에서 사용불가
- VIP 고객에게 제공하는 할인율, 세일 가격 적용을 구현하지 않음
3) 상위 클래스 변수를 사용하기 위한 protected 예약어
customerGrade 변수에서 발생한 오류를 해결하기 위해 private이 아닌 protected로 선언한다.
그리고 protected로 선언한 변수를 사용하기 위해 get(), set() 메서드를 추가한다.
protected는 상위 클래스의 변수나 메서드를 외부 클래스에서는 사용할 수 없지만 하위 클래스에서는 사용할 수 있도록 하는 예약어다. 상속된 하위 클래스를 제외한 나머지 외부 클래스에서는 private과 동일한 역할을 한다.
4) 상속 클래스 테스트하기(CustomerTest1.java)
VIPCustomer가 Customer를 상속했기 때문에 Customer의 변수, 메서드를 사용할 수 있다.
2. 상속에서 클래스 생성과 형 변환
1. 하위 클래스가 생성되는 과정
상속을 받은 하위 클래스는 상위 클래스의 변수와 메서드를 사용할 수 있다. 그럴 수 있는 이유는 뭘까?
상위 클래스를 상속받은 하위 클래스가 생성될 때는 반드시 상위 클래스의 생성자가 먼저 호출된다. 그리고 상위 클래스 생성자가 호출될 때 상위 클래스의 멤버 변수가 메모리에 생성되는 것이다.
상위 클래스의 private 변수는 생성은 되지만 단지 하위 클래스에서 접근할 수 없을 뿐이다.
2. 부모를 부르는 예약어 super
super는 하위 클래스에서 상위 클래스로 접근할 때 사용하는 예약어다. 하위 클래스는 상위 클래스의 주소(참조)값을 알고 있다.
1) 상위 클래스 생성자 호출하기
하위 클래스 생성자만 호출했는데 상위 클래스 생성자가 자동으로 호출되는 이유는 하위 클래스 생성자에서 suepr()를 자동으로 호출하기 때문이다. spuer()를 호출하면 상위 클래스의 디폴트 생성자가 호출된다.
2) super 예약어로 매개변수가 있는 생성자 호출하기
Customer 클래스의 디폴트 생성자를 없애고 새로운 생성자를 작성하면 VIPCustomer 생성자가 호출될 때 오류가 발생한다. 묵시적으로 호출될 디폴트 생성자 Customer()가 정의되지 않았기 때문에 반드시 명시적으로 다른 생성자를 호출해야한다는 것이다.
즉, 하위 클래스 생성자를 호출하면 묵시적으로 상위 클래스의 디폴트 생성자를 호출한다.
만약, 상위 클래스에서 매개변수가 있는 생성자를 제공해야한다면 하위 클래스 생성자 내에 명시적으로 매개변수가 있는 다른 생성자를 호출해야한다.
3) 상위 클래스의 멤버 변수나 메서드를 참조하는 super
상위 클래스에서 선언한 멤버 변수나 메서드를 하위 클래스에서 참조할 때 super를 사용한다.
하위 클래스에서 동일한 이름의 상위 클래스 메서드를 가리킬 때 super.메서드명 으로 사용한다.
3. 상위 클래스로 묵시적 클래스 형 변환
모든 하위 클래스는 상위 클래스 자료형으로 형변환 될 수 있지만 그 역은 성립하지 않는다.
(하위 클래스 형은 하위 클래스 형이면서 동시에 상위 클래스형이기도 하므로)
1) 형변환된 vc 가 가리키는 것
하위 클래스의 인스턴스가 상위 클래스로 형 변환되는 과정이 묵시적으로 이루어진다.
클래스의 상속 계층이 여러 단계일 경우도 상위 클래스로의 형 변환은 묵시적으로 이루어진다.
클래스가 형변환 되었을 때는 선언한 클래스형에 기반하여 멤버 변수와 메서드에 접근할 수 있다.
3. 메서드 오버라이딩
1. 상위 클래스 메서드 재정의하기
오버라이딩이란 상위 클래스에 정의한 메서드가 하위 클래스에서 구현할 내용과 맞지 않을 경우, 하위 클래스에서 메서드를 재정의하는 것이다. 오버라이딩을 하려면 반환형, 메서드 이름, 매개변수 개수, 매개변수 자료형이 반드시 같아야 한다! 그렇지 않으면 자바 컴파일러가 다른 메서드로 인식하게 된다.
@Override 어노테이션은 '이 메서드는 재정의된 메서드입니다'라고 컴파일러에게 알려주는 역할을 한다.
2. 묵시적 클래스 형 변환과 메서드 재정의
상속에서 상위 클래스와 하위 클래스에 같은 이름의 메서드가 존재할 때 호출되는 메서드는 인스턴스에 따라 결정된다. 즉 선언한 클래스형이 아닌 생성된 인스턴스의 메서드를 호출하는 것이다.
3. 가상 메서드
인스턴스의 메서드가 호출되는 기술을 가상 메서드라고 한다.
지역 변수는 스택 메모리에 위치하고 멤버 변수는 인스턴스가 생성될 때마다 힙 메모리에 새로 생성된다.
메서드의 명령 집합은 메서드 영역에 위치하며 메서드를 호출할 때마다 메서드 영역의 주소를 참조하여 명령이 실행된다. 따라서 인스턴스가 달라도 동일한 메서드가 호출된다.
<가상 메서드의 원리>
메서드를 호출한다는 것은 그 메서드의 명령 집합이 있는 메모리 위치를 참조하여 명령을 실행하는 것이다. 그런데 가상 메서드의 경우는 가상 메서드 테이블에서 주소 값을 찾아 해당 메서드의 명령을 수행한다.
(가상 메서드 테이블은 각 메서드 이름과 실제 메모리 주소가 짝을 이루고 있음)
그러므로 재정의된 메서드는 실제 인스턴스에 해당하는 메서드가 호출되고 재정의되지 않은 메서드는 상위 클래스의 메서드가 호출된다.
4. 다형성
1. 다형성이란?
다형성이란 하나의 코드가 여러 자료형으로 구현되어 실행되는 것을 말한다.
다형성은 추상 클래스, 인터페이스에서 구현된다.
상속 관계에 있는 상위 클래스와 하위 클래스느 같은 상위 클래스 자료형으로 선언되어 생성할 수 있지만 재정의된 메서드는 각각 호출될 뿐 아니라 이름이 같은 메서드가 서로 다른 역할을 구현한다.
2. 다형성의 장점
1) 상속받은 모든 클래스를 하나의 상위 클래스로 쉽게 관리할 수 있다.
2) 상위 클래스에서 공통 부분의 메서드를 제공하고 하위 클래스에서는 그에 기반한 추가 요소를 덧붙여 구현하면 코드 양이 줄고 유지보수도 편리하다.
3) 다형성에 의해 각 클래스의 여러가지 구현을 실행할 수 있어 프로그램을 쉽게 확장할 수 있음
5. 다형성 활용하기
상속과 다형성을 이용하면 프로그램 유지보수에 매우 편리하다. 이때 배열을 함께 사용하면 여러 하위 클래스 자료형을 상위 클래스 자료형으로 한꺼번에 관리할 수 있다.
1. 일반 고객과 VIP 고객의 중간 등급 만들기(GoldCustomer.java, CustomerTest.java)
import java.util.ArrayList;
public class CustomerTest {
public static void main(String[] args) {
// 배열에는 Customer, GoldCustomer, VIPCustomer 모두 사용O
ArrayList<Customer> customerList = new ArrayList<Customer>();
// 모두 Customer형으로 묵시적 형변환됨
Customer customerLee = new Customer(10010, "이순신");
Customer customerShin = new Customer(10020, "신사임당");
Customer customerHong = new GoldCustomer(10030, "홍길동");
Customer customerYul = new GoldCustomer(10040, "이율곡");
Customer customerKim = new VIPCustomer(10050, "김유신", 12345);
customerList.add(customerLee);
customerList.add(customerShin);
customerList.add(customerHong);
customerList.add(customerYul);
customerList.add(customerKim);
//...
}
}
2. 상속은 언제 사용할까?
1) 상속을 항상 사용하는 것이 좋을까?
상속은 IS-A 관계(일반적인 개념과 구체적인 개념의 관계)일 때 사용하는 것이 가장 효율적이다.
일반 클래스를 점자 구체화하는 상황에서 상속을 사용해야한다.
HAS-A 관계(한 클래스가 다른 클래스를 소유하는 관계)일 때는 상속이 아닌 멤버 변수로 사용하는 것이 적절하다.
(참고) 자바는 다중 상속을 지원하지 않는다. (다중 상속의 모호성 떄문)
6. 다운 캐스팅과 instanceof
1. 하위 클래스로 형 변환, 다운 캐스팅
필요에 따라 다시 원래 인스턴스의 자료형으로 되돌아가야하는 경우가 있다. 상위 클래스로 형 변환되었던 하위 클래스를 다시 원래 자료형으로 형 변환하는 것을 다운 캐스팅이라고 한다.
2. instanceof
다운 캐스팅을 하기 전에 상위 클래스로 형 변환된 인스턴스의 원래 자료형을 확인해야 변환할 때 오류를 막을 수 있다. 이를 확인하는 예약어가 instanceof 다.
instanceof는 왼쪽에 있는 변수의 원래 인스턴스형이 오른쪽 클래스 자료형인가를 확인하고 반환 값이 true일 떄만 다운 캐스팅을 해야한다.
Animal hAnimal = new Human();
//Animal hAnimal = new Tiger();
// hAnimal 인스턴스 자료형이 Human이면
if(hAnimal instanceof Human) {
Human human = (Human)hAnimal; // hAnimal을 Human 형으로 다운 캐스팅
}
주석되어 있는 부분처럼 원래 hAnimal이 Tiger 형이었는데 (Human)으로 다운 캐스팅을 하는 것은 오류를 발생시킨다.
'Java > Do It! 자바 프로그래밍' 카테고리의 다른 글
[JAVA] 10. 인터페이스 (0) | 2022.05.07 |
---|---|
[JAVA] 09. 추상 클래스 (0) | 2022.05.06 |
[DoItJava] 07. 배열과 ArrayList (0) | 2022.05.04 |
[DoItJava] 06. 클래스와 객체2 (0) | 2022.05.03 |
[DoItJava] 05. 클래스와 객체1 (0) | 2022.05.03 |