상속(Inheritance)
- 클래스 간의 관계를 부모(상위), 자식(하위)로 바라보는 개념
- 재사용, 확장이 가능
- extends 키워드를 사용해서 상속 관계를 구현
재사용성
public class Parent
{
public String name = "부모";
public int age = 60;
public void introduce()
{
System.out.println("부모 입니다.");
}
}
class Child extends Parent
{
}
public class Main
{
public static void main(String[] args)
{
Child child = new Child();
System.out.println(child.age); // 부모의 속성을 물려받아 사용
System.out.println(child.name); // 부모의 속성을 물려받아 사용
child.introduceFamily(); // 부모의 메서드를 물려받아 사용
}
}
super
public class Child extends Parent
{
private String name = "자식"
public void superExample()
{
System.out.println("this.name : " + this.name); // "자식"
System.out.println("super.name : " + super.name); // "부모"
}
}
super()
- 부모가 생성된 뒤 자식이 생성되어야 함
- 자식의 생성자를 따로 구현하는 경우, super() 생성자 가장 먼저 선언해줘야 함
public class Parent
{
public Parent() {} // 부모 생성자
}
public class Child extends Parent
{
...
public Child()
{
super(); // 부모클래스 생성자를 먼저 호출
...
}
}
확장
- 부모 클래스의 기능을 유지하면서 자식 클래스의 기능 확장 가능
public class Child extends Parent
{
...
public void option() // 자식에만 있는 기능
{
System.out.println("자식에만 있는 메서드");
}
}
public class Main
{
public static void main(String[] args)
{
...
child.option(); // 자식에만 있는 기능
}
}
재정의 - 메서드 오버라이딩 (overriding)
- 오버라이딩을 통해 부모클래스의 기능을 재정의
- @Override 키워드를 붙이는 것을 권장 (없어도 동작함) (컴파일러가 개발자에게 경고를 줘서 실수 방지 가능)
- 메서드 이름, 매개변수, 반환타입이 동일해야 함
- 접근 제어자는 부모보다 강한 수준으로만 변경 가능
public class Parent
{
...
public void introduce()
{
System.out.println("부모 입니다");
}
}
class Child extends Parent
{
...
@Override
void introduce() // 재정의
{
System.out.println("자식 입니다 (오버라이드)");
}
}
public class Main
{
public static void main(String[] args)
{
Child child = new Child();
child.introduce(); // 출력 "자식 입니다. (오버라이드)"
}
}
추상 클래스
- 공통 기능을 제공하면서 하위 클래스에 특정 메서드 구현을 강제하기 위해 사용
- abstract 키워드로 클래스 선언
- abstract 키워드로 메서드를 선언하면 자식 클래스에서 강제로 구현해야 함
- 추상 클래스로 객체 생성 불가능
abstract class Character
{
private String name;
abstract void attack(); // 추상 메서드: 상속 받은 자식은 강제 구현해야 함
public void potion() // 자식 클래스에서 재사용가능
{
System.out.println("HP 회복");
}
}
public class Warrior extends Character
{
@Override
void attack() {
System.out.println("칼로 슈슈슉"); // 자식 클래스에서 강제 구현해야 함
}
}
public class Main
{
public static void main(String[] args)
{
Character character = new Character(); // ❌ 추상클래스는 구현할 수 없음
Warrior warrior = new Warrior();
warrior.attack(); // 강제 구현한 메서드 사용
warrior.potion(); // 부모클래스의 매서드 사용
}
}
추상 클래스와 인터페이스의 차이점
- 상속이 계층적 구조를 선언하기 적합
- 인터페이스는 표준을 제공하는데 적합
- 인터페이스는 인스턴스 변수 선언 불가능
- 계층적 구조를 표현하면서 공통 속성과 기능을 재사용할 때 추상 클래스를 사용하는 것이 적합