본문 바로가기
Java/객체 지향

객체 지향 원칙 2 - 상속(Inheritance)

by 정구정구 2026. 6. 4.

상속(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(); // 부모클래스의 매서드 사용
    }
}

 

추상 클래스와 인터페이스의 차이점

  • 상속이 계층적 구조를 선언하기 적합
  • 인터페이스는 표준을 제공하는데 적합
  • 인터페이스는 인스턴스 변수 선언 불가능
  • 계층적 구조를 표현하면서 공통 속성과 기능을 재사용할 때 추상 클래스를 사용하는 것이 적합