class Parent { ... }
class Child extends Parent { ... }
Parent pa = new Parent(); // 허용
Child ch = new Child(); // 허용
Parent pc = new Child(); // 허용
Child cp = new Parent(); // 오류 발생.
예제
class Tv{
boolean power; // 전원상태(on/of)
int channel; // 채널
void power() { power = !power; }
void channelUp() { ++channel; }
void channelDown() { --channel; }
}
class CaptionTv extends Tv {
String text; // 캡션을 보여주기 위한 문자열
void caption() { /* 내용 생략 */ }
}
CaptionTv c = new CationTv();
Tv t = new CationTv();
위처럼 CationTv인스턴스 2개를 생성하고 참조변수 c와 t가 생성된 인스턴스를 하나씩 참조하도록 하였다.
두 참조변수의 차이점은 인스턴스가 CaptionTv타입이라 할지라도, 참조변수 t로 CaptionTv인스턴스의 모든 멤버를 사용할 수 없다.
조상 클래스에서 상속을 받아 오버라이팅된 메서드만 사용이 가능하고, 오버라이팅된 메서드로 실행된다.
형변환
class Parent { ... }
class Child extends Parent { ... }
class Brother extends Parent { ... }
Parent pa1 = new Parent();
Parent pa2 = null;
Child ch = new Child();
Child br = null;
pa2 = ch; // 타입 변환을 생략할 수 있음.
br = (Brother)pa1; // 타입 변환을 생략할 수 없음.
br = (Brother)ch; // 직접적인 상속 관계가 아니므로, 오류 발생.
추상 클래스
추상 메서드
abstract class Player {
int currentPos; // 현재 Play되고 있는 위치를 저장하기 위한 변수
Player() {
currentPos = 0;
}
abstract void play(int Pos); // 추상 메서드
abstract void stop();
void paly() {
play(currentPos); // 추상메서드 사용
}
}
메서드를 이와 같이 미완성 상태로 남겨 놓은 이유는 메서드의 내용이 상속받은 클래스에 따라 달라질 수 있기 때문에 조상 클래스에서는 선언부만을 작성하고, 주석을 덕붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워 두는 것이다.
예제
abstract class Pokemon { // 포켓몬
String name;
String Characteristic;
abstract void skill1();
abstract void skill2();
abstract void skill3();
abstract void skill4();
}
class Pikachu extends Pokemon { // 피카츄
@Override
void skill1() {
System.out.println("10만볼트");
}
@Override
void skill2() {
System.out.println("번개");
}
@Override
void skill3() {
System.out.println("볼트태클");
}
@Override
void skill4() {
System.out.println("전광석화");
}
}
class Eevee extends Pokemon { // 이브이
@Override
void skill1() {
System.out.println("꼬리흔들기");
}
@Override
void skill2() {
System.out.println("울음소리");
}
@Override
void skill3() {
System.out.println("몸통박치기");
}
@Override
void skill4() {
System.out.println("애교부리기");
}
}
interface InterName {
public static final 상수변수 = value;
public abstract 메서드이름(매개변수 목록);
}
인터페이스 상속
interface Movable {
// 지정한 위치로 이동하는 기능의 메서드
void move(int x, int y);
}
interface Attackable {
// 지정한 대상을 공격하는 기능의 메서드
void attack(Unit u);
}
interface Fightable extends Movable, Attackable { }
인터페이스 구현
인터페이스를 상속할 때 일반 클래스나 추상 클래스는 확장한다는 의미의 'extends'를 사용하지만 인터페이스는 구현한다는 의미의 'implements'를 사용한다.
class Fighter implements Fightable {
public void move(int x, int y) { code... }
public void attack(Unit u) { code... }
}
만약 구현하는 인터페이스의 메서드 중 일부만 구현한 다면, abstract를 붙여서 추상클래스로 선언해야 한다.
그리고 다음과 같이 상속과 구현을 동시에 할 수도 있다.
class Fighter extends Unit implements Fightalbe {
public void move(int x, int y) { code... }
public void attack(Unit u) { code... }
}
인터페이스의 장점