1. 상속을 씀으로써 얻을 수 있는 기대효과
(1) 코드의 재사용성을 높이고 코드의 중복성을 제거할 수 있다.
(2) 프로그램의 생산성과 유지보수에 크게 기여된다.
2. 부모와 아이
- 부모는 조상, 상위, 기반 클래스라고도 불리어진다.
- 아이는 자손, 하위, 파생된 클래스라고도 불리어진다.
( age는 부모에서 생성된 age이다. )
( 이처럼 age는 아이에게 포함되므로 부모에서 정의한 것을 같이 사용할 수 있다. )
3. 상속될 때 규칙
(1) 생성자와 초기화 블럭은 상속되지 않는다. 맴버만 상속될 수 있다.
(2) 항상 상위 클래스보다 하위클래스는 같거나 많은 맴버를 갖는다.
4. 간접적인 상속 관계
( GrandChild와 Parent 관계가 있을 때, 우리는 간접적인 상속 관계라고 부른다. )
5. 클래스 간의 관계: 포함관계
- 상속이외에도 클래스를 재사용하는 또 다른 방법이 있는데, 그것은 클래스 간에 '포함' 관계를 맺어 주는 것이다.
- 클래스 간의 포함 관계를 맺어 주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조 변수를 선언하는 것을
뜻한다.
- 아래의 예제를 통해 이해하자.
( 위는 평범한 코드지만, 포함 관계를 쓰면 아래의 코드처럼 바뀐다. )
( Circle이 Point를 포함함으로써 '원은 점을 가지고 있다' 라는 뜻이 된다. )
( 이렇게 해준다면, 클래스를 작성하는 것이 쉽고 코드도 간결해서 이해하기 쉽다. )
( 또한 단위 클래스별로 코드가 작게 나뉘어 작성되어 있기 때문에 코드를 관리하는데도 수월하다. )
6. 클래스 간의 관계 결정하기: 상속 vs 포함
- 상속이냐 포함이냐 를 따질 때, 우리는 '~은 ~이다'(상속)와 '~은 ~을 가지고 있다'(포함) 를 넣어서 문장을 만들어보면 클래스 간의 관계가 보다 명확해진다.
- 포함은 위의 예제로 따지면 '원은 점이다' 와 '원은 점을 가진다' 중에 옳은 문장은 후자가 된다.
- 상속은 예를 들면 '사람은 부모이다' 와 '부모는 사람이다' 중에 옳은 문장은 후자가 된다.
7. 예제(1) - 배열로 객체 선언하고 반환해보기.
( '원은 도형이다' 와 '원은 점을 가진다' 가 옳은 문장이므로, 위의 예제처럼 잘 결정해야 한다. )
8. 예제(4) - 예제(1)을 실제 활용해보는 예제이다.
public class Exercise001 {
public static void main(String[] args) {
Point[] p = { new Point(100, 100),
new Point(140, 50),
new Point(200, 100)
};
Triangle t = new Triangle(p);
Circle c = new Circle(new Point(150, 150), 50);
t.draw(); // 삼각형을 그린다.
c.draw(); // 원을 그린다.
}
}
class Shape {
String color = "black";
void draw() {
System.out.printf("[color=%s]%n", color);
}
}
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point() {
this(0,0);
}
String getXY() {
return "("+x+","+y+")"; // x와 y의 값을 문자열로 반환
}
}
class Circle extends Shape {
Point center; // 원의 원점좌표
int r; // 반지름
Circle() {
this(new Point(0, 0), 100); // Circle(Point center, int r)를 호출
}
Circle(Point center, int r) {
this.center = center;
this.r = r;
}
void draw() { // 원을 그리는 대신에 원의 정보를 출력하도록 했다.
System.out.printf("[center=(%d, %d), r=%d, color=%s]%n", center.x, center.y, r, color);
}
}
class Triangle extends Shape {
Point[] p = new Point[3];
Triangle(Point[] p) {
this.p = p;
}
void draw() {
System.out.printf("[p1=%s, p2=%s, p3=%s, color=%s]%n", p[0].getXY(), p[1].getXY(), p[2].getXY(), color);
}
}
9. 예제(3) - 배열로 객체 선언하고 반환해보기. (포함)
public class Exercise001 {
public static void main(String[] args) {
Deck d = new Deck(); // 카드 한 벌(Deck)을 만든다.
Card c = d.pick(0); // 섞기 전에 제일 위의 카드를 뽑는다.
System.out.println(c); // System.out.println(c.toString());과 같다.
d.shuffle(); // 카드를 섞는다.
c = d.pick(0); // 섞은 후에 제일 위의 카드를 뽑는다.
System.out.println(c);
}
}
// Deck클래스
class Deck {
final int CARD_NUM = 52; // 카드의 개수
Card cardArr[] = new Card[CARD_NUM]; // Card객체 배열을 포함
Deck () { // Deck의 카드를 초기화한다.
int i=0;
for(int k=Card.KIND_MAX; k > 0; k--)
for(int n=0; n < Card.NUM_MAX ; n++)
cardArr[i++] = new Card(k, n+1);
}
Card pick(int index) { // 지정된 위치(index)에 있는 카드 하나를 꺼내서 반환
return cardArr[index];
}
Card pick() { // Deck에서 카드 하나를 선택한다.
int index = (int)(Math.random() * CARD_NUM);
return pick(index);
}
void shuffle() { // 카드의 순서를 섞는다.
for(int i=0; i < cardArr.length; i++) {
int r = (int)(Math.random() * CARD_NUM);
Card temp = cardArr[i];
cardArr[i] = cardArr[r];
cardArr[r] = temp;
}
}
} // Deck클래스의 끝
// Card클래스
class Card {
static final int KIND_MAX = 4; // 카드 무늬의 수
static final int NUM_MAX = 13; // 무늬별 카드 수
static final int SPADE = 4;
static final int DIAMOND = 3;
static final int HEART = 2;
static final int CLOVER = 1;
int kind;
int number;
Card() {
this(SPADE, 1);
}
Card(int kind, int number) {
this.kind = kind;
this.number = number;
}
public String toString() {
String[] kinds = {"", "CLOVER", "HEART", "DIAMOND", "SPADE"};
String numbers = "0123456789XJQK"; // 숫자 10은 X로 표현
return "kind : " + kinds[this.kind]
+ ", number : " + numbers.charAt(this.number);
} // toString()의 끝
} // Card클래스의 끝
( 여기서 Deck과 Card 클래스의 관계가 무엇인지 확인해본다. )
( Card의 toString 함수에 대해 무엇인지 확인해본다. )