상속
상수를 이용하지 않는 기능 추가의 문제점
- 기존 코드에 기능 추가
- 변경하기 전에 이 클래스를 사용해서 만든 프로젝트에 영향을 줄 수 있다.
- 기존 코드를 손 댔을 때 오류 발생 위험이 있다.
- 프로젝트를 수행할 때 마다 고객의 요구사항을 맞추기 위해 코드를 덧붙이다보면 누더기가 될 수 있다.
- 기존 코드를 복사해서 기능 추가
- 장점 : 기존 코드를 손대지 않는다. ⇒ 기존코드를 사용한 프로젝트에 영향을 주지 않음
- 단점 : 중복코드가 발생됨
- 기능 추가 : 복사 코드에도 기능 추가해야함 ⇒ 유지보수가 어려움
- 기존 코드 버그 수정 : 복사코드도 버그 수정해야함 ⇒ 유지보수가 어려움
상속을 이용할 때
기존 코드를 손대지 않고 기능 추가
1
2
3
| class Car2 extends Car{ - }
// Car2 : 새 클래스(= 자식 클래스, sub class)
// Car : 기존 클래스(= 부모 클래스, super class)
|
- 장점 : 기존 코드를 손대지않는다 ⇒ 기존 코드를 사용한 프로젝트에 영향을 주지 않는다.
상속은 기존 코드를 자동으로 복사해오는 것이 아니다. 기존 코드를 제 것처럼 사용할 수 있는 권한을 획득하는 것이다.
상속과 인스턴스 생성
1
2
| new Score2();
// [ name | kor | eng | math | sum | aver | music | art ]
|
- 서브 클래스의 인스턴스를 만들 때 수퍼 클래스의 인스턴스 필드로 생성한다.
상속과 메서드 호출
1
2
3
4
5
6
7
8
| class A{ void m1(){ - } }
class B extends A{ void m2(){ - } }
class C extends B{ void m3(){ - } }
class D extends C{ void m4(){ - } }
B obj = new B(); // obj > 200[ A | B ]
obj.m2();
obj.m1(); // super class의 코드를 제 것처럼 사용할 수 있다.
|
상속과 클래스 로딩
상속과 생성자, super();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| class Object{ - }
class A extends Object{
int v1;
// public A(){ super(); }
}
class B extends A{
int v2;
// public B(){ super(); }
}
class C extends B{
int v3;
// public C(){ super(); }
}
C obj = new C();
// 사용자가 따로 생성자를 지정하지 않고 호출할 경우 자바가 자동으로 생성자를 만드는데 이때 부모 클래스의 생성자를 호출하는 super()를 컴파일러가 자동 삽입한다.
|
super( )
모든 생성자는 첫 문장으로 슈퍼 클래스의 생성자를 호출하는 코드를 갖고 있다.
개발자가 명시적으로 작성하지 않으면 슈퍼클래스의 default constructor를 호출하는 코드를 자동 삽입한다. ← 컴파일러가 삽입함
1
2
3
4
5
6
7
8
9
10
11
| class A {
int v1;
public A(int a){ super(); }
}
class B{
int v2;
public B(){
super(); // 불가
super(100); // 가능
}
}
|
상속 분류
- Specialization
- 좀 더 특별한 클래스를 정의할 때 사용하는 상속
- Generalization
추상 클래스
- 서브 클래스에 공통 필드나 메서드를 상속해주는 역할
1
| new Car(); // 추상 클래스는 인스턴스 생성이 불가하다.
|
추상 메서드
추상 메서드와 호출
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class Car{
String model, maker, capacity;
abstract void run();
}
class Sedan extends Car{
String sunroof;
run(){ - }
doSunroof(){ - }
}
Car obj = new Sedan(); // 200[ model | maker | capacity | sunroof | ... ]
obj.run(); // 컴파일러 : 레퍼런스의 타입에서 메서드가 있는지 찾음 -> Car class에서 run()을 찾는다
// JVM : 레퍼런스가 실제 가리키는 객체의 클래스에서 찾음 -> Sedan에서 run()을 찾는다.
obj.doSunroof(); // Car class에서 doSunroof가 없어 컴파일러에서 에러가 남
|
다중 상속이 없는 이유
1
2
3
4
5
| C obj = new C();
// 어떤 변수에 넘겨야할지 결정할 수 없다.
obj.v2 = 3.14;
obj.v2 = 100;
|
왼쪽처럼 다중 상속된 C에서 위 코드처럼 값을 넘길 때 A에 넘겨야 할지 B에 넘겨야 할지 판단 불가하다.
그래서 자바는 다중 상속을 지원하지않는다.
다형적 변수
여러 타입의 객체를 참조하는 레퍼런스
1
2
3
4
5
6
7
8
9
10
11
12
13
| class X{ - }
class A extends X{ - }
class B extends X{ - }
class C extends B{ - }
X obj; // 다형적 변수 : 슈퍼 클래스인 X로 선언했기 때문에 A, B, C를 모두 받을 수 있는 변수이다.
obj = new X();
obj = new A();
obj = new B();
obj = new C();
obj.인스턴스 변수 // X의 서브 클래스는 무조건 X의 인스턴스 변수를 갖는다. (= 자식 클래스의 인스턴스는 부모 클래스의 인스턴스 변수를 갖는다.)
obj.인스턴스 메서드 // X의 인스턴스 변수를 사용하는 인스턴스 메서드
|
레퍼런스와 인스턴스 변수
1
2
3
4
5
6
7
8
9
10
11
12
| class X{ - }
class A extends X{ - }
class B extends X{ - }
class C extends B{ - }
B obj; // 이 레퍼런스를 이용하여 B, X의 인스턴스 변수를 사용 할 수 있어야한다.
obj = new X(); // 생성된 객체 [ X ] -> 불가
obj = new A(); // 생성된 객체 [ X | A ] -> 불가
obj = new B(); // 생성된 객체 [ X | B ] -> 가능
obj = new C(); // 생성된 객체 [ X | B | C ] -> 가능
C obj = new C();
|
결론. 레퍼런스는 자식 클래스의 인스턴스 주소를 저장해도 된다. → 변수에 여러 타입의 객체 주소 저장 가능 = 다형적 변수
다형적 변수 - 상속관계
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| class Vehicle{
String model, capacity;
}
class Bike extends Vehicle{
String engine;
}
class Car extends Vehicle{
String cc, value;
}
class Sedan extends Car{
String sunroof, auto;
}
class Truck extends Car{
String ton, zip;
}
Bike b = new Bike(); // 200[ modle | capacity | engine ]; [ vehicle 변수 | Bike 변수 ]
b.Vehicle 멤버(필드, 메서드) // 가능
b.Bike 멤버 // 가능
Vehicle v = b; // 200
v.Vehicle 멤버 // 가능
v.Bike 멤버 // 컴파일 오류
|
this와 super 키워드와 필드 접근
this와 super 키워드와 메서드 접근
다형적 변수와 메서드 호출
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| class A{
m(){ - };
}
class A2 extends A{
m(){ - };
x(){ - };
}
class A3{
y(){ - };
}
A obj = new A();
obj.m(); // A.m()
((A2)boj).x(); // 컴파일 OK | 실행 NO > 예외발생
A2 obj2 = new A2();
obj2.m(); // A2.m()
obj2.x(); // A2.x()
A obj3 = new A3();
obj3.m(); // A2.m()
obj3.y(); // 컴파일 오류
((A3)obj3).y(); // 컴파일 OKc A3.y()
|