상속
- 기존의 클래스로 새로운 클래스를 작성하는 것(코드의 재사용)
- 두 클래스를 부모와 자식으로 관계를 맺어주는 것
class Car {}
class FireEngine extends Car {}
- 자손은 조상의 모든 멤버를 상속받는다.(생성자, 초기화블럭 제외)
- 왜 자손과 조상이라는 단어를 사용했느냐?
- 부모의 부모도 있을 수 있다. 바로 위에 부모것만 상속받는 게 아니기 때문이다.
- 자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다.)
- 자손의 변경은 조상에 영향을 미치지 않는다.
- 자식 클래스의 변경이 있어도 조상에 영향이 가지 않는다.
class Tv {
boolean power; // 전원상태(on/off)
int channel; // 채널
void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class CaptionTv extends Tv {
boolean caption; // 캡션상태(on/off)
void displayCaption(String text) {
if (caption) { // 캡션 상태가 on(true)일 때만 text를 보여 준다.
System.out.println(text);
}
}
}
class CaptionTvTest {
public static void main(String args[]) {
CaptionTv ctv = new CaptionTv();
ctv.channel = 10; // 조상 클래스로부터 상속받은 멤버
ctv.channelUp(); // 조상 클래스로부터 상속받은 멤버
System.out.println(ctv.channel);
ctv.displayCaption("Hello, World");
ctv.caption = true; // 캡션기능을 켠다.
ctv.displayCaption("Hello, World"); // 캡션을 화면에 보여 준다.
}
}
포함 관계
- 포함(composite)이란?
- 클래스의 멤버로 참조변수를 선언하는 것
- 작은 단위의 클래스를 만들고, 이들을 조합해서 클래스를 만든다.
- circle이 point를 포함한 것. = 포함 관계
class Circle { Point c = new Point(); //원점 int r; //반지름 }
왼쪽, 오른쪽 둘 다 저장공간이 3개인 건 같다.
하지만 오른쪽은 참조변수 c가 가리키는 객체의 c가 가리키는 x
즉 `c.c.x`, `c.c.y` 다.
왼쪽보다 오른쪽이 복잡도가 더 줄어드는 거다.
클래스 간의 관계 결정하기
- 상속관계
- ~은 ~이다 (is-a)
- 포함관계
- ~은 ~를 가지고 있다.(has-a)
단일상속
- Java는 단일상속만을 허용한다(C++은 다중상속 서용)
class TvDVD extends Tv, DVD { } //에러. 조상은 하나만 허용된다.
왜일까..?
→ 인터페이스를 이용하면 충돌을 해결하면서 다중상속과 같은 효과를 낼 수 있다!
→ 만약 `Tv`, `DVD`에 같은 이름의 메서드가 있다면 어느 걸 상속받아야 하는지 충돌 문제가 있기 때문에
- 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다.
Object클래스
- 모든 클래스의 조상
- 부모가 없는 클래스는 컴파일러에 의해 자동적으로 `Object`클래스를 상속받게 된다.
오버라이딩
- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것
오버라이딩의 조건 3가지
- 선언부가 조상 클래스의 메서드와 일치해야 한다,
- 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
- 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
class Car {
void method1() throws IOException, Exception {
}
}
class FireEngine extends Car {
void method1() throws IOException, SQLException, Exception { //안됨!
}
}
참조변수 super, 생성자 super()
참조변수 super
- 객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자) 내에만 존재한다.
- 조상의 멤버를 자신의 멤버와 구별할 때 사용
class SuperTest {
public static void main(String args[]) {
Child c = new Child();
c.method();
}
}
class Parent {
int x=10;
}
class Child extends Parent {
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x="+ super.x);
}
}
//결과
//10
//10
//10
super() - 조상의 생성자
- 조상의 생성자를 호출할 때 사용
- 조상의 멤버는 조상의 생성자를 호출해서 초기
PointChild(int x, int y, int z){
super(x, y); //조상클래스의 생성자를 호출
this.z = z; //자신의 멤버를 초기
}
이렇게 조상의 멤버를 초기화하면 안 된다!
아래처럼 조상에게 초기화를 위임해야 한다.
PointChild(int x, int y, int z){
super(x, y); //조상클래스의 생성자를 호출
this.z = z; //자신의 멤버를 초기
}
많이들 모르는 조건이 또 하나 있다! 🌟 정말 중요함 🌟
- 생성자의 첫 줄에 반드시 생성자를 호출해야 한다.
- 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입한다.
에러의 원인을 찾으시오
- point3D의 생성자 호출에서 에러 발생
위에서 생성자의 첫 줄에 생성자를 호출하지 않으면 컴파일러가 `super();`를 자동으로 삽입한다고 했다.
→ `Point();` 실행
에러 발생!
왜냐면 Point 생성자가 이미 있기 때문에 기본 생성자가 자동으로 삽입되지 않는다.
그래서 `Point();`가 없기 때문에 에러가 발생한 것
해결방법
→ Point3D의 생성자에서 `super(x, y);`를 호출했다면 에러가 나지 않았을 것.
'📝 끄적끄적 > 🖥️ 자바의 정석' 카테고리의 다른 글
[자바의 정석] - 추상 클래스와 추상메서드 (0) | 2023.09.25 |
---|---|
[자바의 정석] 참조변수의 형변환, instanceof 연산자 (0) | 2023.09.24 |
[자바의 정석] 제어자, 캡슐화 (0) | 2023.09.24 |
[자바의 정석] 생성자, 변수/멤버 변수의 초기화 (0) | 2023.09.22 |
[자바의 정석] static 메서드와 인스턴스 메서드, 오버로딩 (0) | 2023.09.21 |
[자바의 정석] 기본형/참조형 매개변수, 참조형 반환타입 (0) | 2023.09.20 |