기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것.
새로 작성하는 클래스의 이름 뒤에 extends
키워드와 기존 클래스 이름을 작성
class ChildClass extends ParentClass {
...
}
이 때 상속해주는 쪽을 조상 클래스, 상속 받는 쪽을 자손 클래스라고 부름.
자손 클래스는 조상 클래스의 멤버(변수와 메서드)를 모두 포함함.
생성자와 초기화 블럭은 상속 안됨. 멤버만 상속.
조상 클래스에 변경 사항이 생기면 자손 클래스에도 영향이 가지만, 반대의 경우는 해당사항이 없음
클래스 간에 포함(composite) 관계를 만들어주면 클래스를 효율적으로 재사용할 수 있음.
class Circle {
int x; // 원점의 x 좌표
int y; // 원점의 y 좌표
int r; // 반지름
}
class Point {
int x; // x 좌표
int y; // y 좌표
}
Circle
클래스의 멤버 변수인 원점의 좌표들은 Point
클래스를 활용하여 나타낼 수 있음
class Circle {
Point c = new Point();
int r =;
}
이렇게 다른 클래스를 멤버 변수로 활용하는 포함 관계를 통해 좀 더 구조적인 코드를 짤 수 있음.
상속 관계, 포함 관계를 각각 어떻게 구분하여 적용해주면 좋은가?
상속 관계: A는 B이다(또는 B의 일종이다)
포함 관계: A는 B를 가지고 있다
예시)
Rectangle은 Point이다 (X)
Rectangle은 Point를 가지고 있다 (O)
→ 포함 관계로 설정
class Rectangle {
Point[] p = new Point[4];
...
}
Rectangle은 Polygon이다. (O)
→ 상속 관계로 설정
class Rectangle extends Polygon {
...
}
예시2)
Deck은 Card를 가지고 있다 (포함 관계 성립)
class DeckTest {
public static void main(String[] args) {
Deck d = new Deck();
Card c = d.pick(0); // 덱의 맨 앞 카드 뽑기
System.out.println(c); // 참조변수를 출력하면, Card 클래스에서 오버라이드(override)했던 toString 메서드가 호출됨
d.shuffle();
c = d.pick(0); // 섞인 덱에서 맨 앞 카드 뽑기
System.out.println(c);
}
}
class Deck {
final int TOTAL_COUNT = 52;
Card[] cardArr = new Card[TOTAL_COUNT];
Deck() {
int i = 0;
for (int kind = Card.KIND_MAX; kind > 0; kind--) {
for (int num = 0; num < Card.NUM_MAX; num++) {
cardArr[i++] = new Card(kind, num + 1);
}
}
}
Card pick(int index) {
return cardArr[index];
}
Card pick() {
int randomIndex = (int)(Math.random() * TOTAL_COUNT);
return cardArr[randomIndex];
}
void shuffle() {
for (int i = 0; i < cardArr.length; i++) {
int randomIndex = (int)(Math.random() * TOTAL_COUNT);
Card tmp = cardArr[i];
cardArr[i] = cardArr[randomIndex];
cardArr[randomIndex] = tmp;
}
}
}
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 num;
Card() {
this(SPADE, 1);
}
Card(int kind, int num) {
this.kind = kind;
this.num = num;
}
public String toString() {
String[] kinds = {"", "CLOVER", "HEART", "DIAMOND", "SPADE"};
String nums = "0A23456789XJQK";
return String.format("kind: %s num: %c", kinds[this.kind], nums.charAt(this.num));
}
// 조상 클래스인 Object의 메서드 중 toString을 오버라이드(override)한 것.
}
클래스 안에
toString
메서드를 오버라이드 해놓으면, 인스턴스를 출력하거나 참조변수를 문자열과 연산할 때 자동적으로 문자열로 변환시켜줌.
쉽게 말해 동시에 여러 부모로부터 상속 받을 수 없다는 뜻.
다중 상속을 허용하는 C++
과는 다르게 Java
에서는 클래스간의 명확한 관계 형성을 위해 단일 상속만을 허용함.
다중 상속의 문제점: 서로 다른 부모클래스로부터 이름이 겹치는 멤버들을 받아오면 구별할 수 없음.
모든 클래스는 Object
클래스의 상속을 받음.
따라서 Java
의 모든 클래스에서는 Object
클래스의 멤버들을 사용할 수 있음. (이후에 다뤄질 예정)