상속
상속(inheritance)
- 거의 모든 사람이 OOP의 핵심이라 여기는 특성
- 초창기 OO에서 가장 중요한 특성이라 여김
- 현재에도 상속을 지원하지 않으면 OO 언어라고 안 보는 게 보통
- OOP의 또 다른 매우 중요한 특성인 다형성의 기반
OOP에서의 상속이란?
이미 존재하는 클래스를 기반으로 새 클래스를 만드는 방법
새 클래스는 기존 클래스의 동작과 상태를 그대로 물려 받음(유전)
그 외에 새 클래스만의 동작과 상태를 추가 가능(진화)
물론 이 새 클래스를 상속해서 또 다른 클래스를 만들 수 있음
이미 존재하는 클래스를 부르는 이름
- 부모(parent) 클래스
- 기반(base) 클래스
새 클래스를 부르는 이름
- 자식(child) 클래스
- 파생(derived) 클래스
두 클래스 간의 상속 관게를 설명하는 표현
- 자식 클래스가 부모 클래스를 상속 받았다
- 자식 클래스가 부모 클래스로부터 파생되었다
- 자식 클래스가 부모 클래스의 한 종류이다 (is-a)
생성자 호출 순서
- 메모리에 개체 생성
- 부모 생성자 호출
- 자식 생성자 호출
Student 생성자에서 Person 생성자 호출하기
public class Person {
// ...
public Person(String firstName, String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
// ...
}
public class Student extends Person {
// ...
public Student(String firstName, String lastName){
super(firstName, lastName);
}
// ...
}
super 키워드
부모클래스의 생성자를 호출할 때
super(<매개변수 목록>)
부모 클래스의 멤버 변수/함수를 호출할 때
super.<부모의 멤버 변수/부모의 메서드>
- super는 현 개체의 부모 부분을 가리킴
- super()라고 코드를 작성하면 부모의 생성자를 호출
- 멤버 변수나 메서드를 호출할 때도 사용 가능
접근 제어자: protected
protected <자료형> <변수명>;
protected <반환형> <함수형> (<매개변수 목록>) {...}
protected class <클래스명> { ... }
- 외부자들은 접근할 수 없음
- 클래스 내부, 같은 패키지에 속한 클래스, 자식 클래스만 접근 가능
- 클래스의 경우 내포된(nested) 클래스에 한 해 붙일 수 있음
is-a 관계
- 상속 관계
- 수학에서 부분 집합 관계
has-a 관계
- 컴포지션 관계
상속 vs 컴포지션
- 둘다 재사용성을 위한 방법
- 상속으로 해결할 수 있는 많은 문제를 컴포지션으로도 가능
- 그 반대도 가능
- 순전히 기술적인 관점
- 역사적으로 사람들의 선호는 왔다 갔다
- 초창기에는 상속을 과도하게 선호
- 그 후 무조건 컴포지션이 답이라는 잘못된 조언을 많이 따랐음(현재 진행형)
- OO에서 큰 결정사항 중 하나: 상속 vs 컴포지션 중 하나를 고르는 것
- 실생활에서 개첻르끼리의 관계를 기준으로 선택할 것
- has-a 관계: 컴포지션
- is-a 관계: 상속
부모를 자식에게 대입할 수 있게 되면...
public static Student = convertToStudent(Person person){
Student student = person;
return student;
}
// 다른 함수 어딘가
convertToString(student);
convertToString(teacher);
convertToString(partTime);
- 메서드 호출은 호출자의 마음!
- Person 및 Person의 자식 클래스를 모두 전달할 수 있음
- 즉, 실행 중에 반드시 Student 개체만 들어온다는 보장이 없음
자식을 부모에 대입하는 건 암시적 캐스팅
- 부모 <- 자식은 사실 캐스팅
- 이걸 컴파일러가 암시적으로 해준 것일 뿐
Student student = new Student("Leon", "Kim");
Person person = (Person) student;
// person 생략
Person person = (Person) student;
그 반대 캐스팅은 반드시 명시적으로
- 자식 <- 부모는 명시적 캐스팅으로만 가능
Student student = new Student("Leon", "Kim");
Person person = student;
// person 생략
Stduent actuallyStudent = (Student) person;
- 부모를 자식으로 캐스팅 후 호출
- 컴파일 잘 됨
전혀 상관없는 클래스로 캐스팅하면?
- 컴파일러가 잡아줌
컴파일러가 못 잡아내는 경우
Person person = new Student("Leon", "Kim");
Teacher teacher = (Teacher) person;
- 이럴 때는 실행 중에 예외 발생
- ClassCastException
우리가 작성하고 싶은 로직
Person person = new Student("Leon", "Kim");
Teacher teacher = (Teacher) person;
- 이 Person 개체가 실제로는 Teacher인지 확인
- 실제로 Teacher인 경우에만 Teacher로 캐스팅
결국 부모형 변수에 저장된 개체가 실제 어떤 자식형인지 알 방법이 필요
그것도 실행 중에!
이걸 RTTI(run time type identification) 기능이라고 함
instanceof 연산자
<변수명> instance of <클래스명>
Person person = new Student("Leon", "Kim");
System.out.printIn(person instanceof Student); // true 출력
System.out.printIn(person instanceof Teacher); // false 출력
- 개체가 특정 클래스의 인스턴스인지 판단하는 연산자
instanceof를 사용해서 고친 코드
Person person0 = new Student("Leon", "Kim");
Person person1 = new Teacher("Pope", "Kim", Department.COMPUTER_SCIENCE);
Teacher teacher = null;
if(person0 instanceof Teacher) {
teacher = (Teacher) person0; // teacher: null
}
if(person1 instanceof Teacher) {
teacher = (Teacher) person1; // teacher: person1
}
instanceof 연산자는 반드시 '특정 클래스'의 인스턴스를 확인하는 게 아님
부모 클래스로 검사해도 true 반환
getClass()
<변수명>.getClass()
FullTimeTeacher teacher = new FullTimeTeacher("Lulu", "Choi", Department.MAGIC);
Class c = teacher.getClass();
- 실행 중에 개체의 클래스 정보를 얻어올 수 있음
- 반환된 개체(Class)에는 여러 유용한 메서드가 들어 있음
getClass().getName()
<변수명>.getClass().getName()
FullTimeTeacher teacher = new FullTimeTeacher("Lulu", "Choi", Department.MAGIC);
Class c = teacher.getClass().getName(); // academy.pocu.FullTimeTeacher
- 클래스명을 반환하는 메서드
- 이 때, 클래스명은 패키지 경로까지 포함
언제 사용?
- getClass()를 편하게 사용할 수 있는 경우가 종종 있음
- 주로 클래스 이름을 찾을 때
- 클래스 안에 있는 메서드나 멤버 변수 등도 찾을 수 있음
- getClass().getName()은 정말 많이 사용
- 예: 로그 메시지를 출력할 때
좋아 보이는 RTTI 그러나...
- 매니지드 언어들은 보통 RTTI를 지원
- 단, 그만큼 실행 중에 뭔가 더 해야 함
- 성능 또는 메머리가 중요한 경우에는 별로인 기능
- C/C++ 등의 언어에서는 RTTI 지원이 없거나 사용을 안 함
Object 클래스
- Java의 모든 클래스는 Object라는 클래스를 상속
- 즉, 앞에서 Person[]에 넣었던 개체를 Object[]에도 넣을 수 있음
- 모든 클래스는 Object를 상속 받으니 그 메서드들도 같이 딸려옴
- Object에는 유용한 메서드들이 좀 있음
- RTTI도 그 중 하나
'프로그래머 > Java Managed Programming' 카테고리의 다른 글
[개체지향 프로그래밍] static | 싱글턴 | 내포 클래스 (0) | 2021.03.01 |
---|---|
[개체지향 프로그래밍] 개체 모델링 | 클래스 다이어그램 | 유연성 | OOP (0) | 2021.02.13 |
[개체지향 프로그래밍] 접근 제어자 | getter/setter | 캡슐화 | 추상화 (0) | 2021.02.07 |
[개체지향 프로그래밍] 개체 생성 | 가비지 콜렉터(garbage collector) | 생성자(constructor) (0) | 2021.02.07 |
[개체지향 프로그래밍] 클래스(class) | 접근 제어자(public, private) | 인스턴스(instance) (0) | 2021.02.07 |