자바 상속 개념과 활용

상속의 기본 원리

객체지향 프로그래밍에서 상속은 클래스 간의 관계를 정의하는 핵심 메커니즘입니다. 자바에서는 extends 키워드를 사용하여 한 클래스가 다른 클래스의 속성과 동작을 물려받도록 할 수 있습니다.

class Vehicle {
    protected String brand;
    
    public void startEngine() {
        System.out.println("엔진을 시동합니다.");
    }
}

class Car extends Vehicle {
    private int doors;
    
    public void openTrunk() {
        System.out.println("트렁크를 엽니다.");
    }
}

생성자 호출 순서

자식 클래스 인스턴스 생성 시 부모 클래스의 생성자가 먼저 실행됩니다. 명시적으로 호출하지 않으면 기본 생성자가 자동으로 호출됩니다.

class Animal {
    public Animal() {
        System.out.println("동물이 생성되었습니다.");
    }
    
    public Animal(String name) {
        System.out.println(name + " 동물이 생성되었습니다.");
    }
}

class Dog extends Animal {
    public Dog() {
        super("포메라니안");
        System.out.println("강아지 객체 완료");
    }
}

// 실행 결과:
// 포메라니안 동물이 생성되었습니다.
// 강아지 객체 완료

메서드 오버라이딩

하위 클래스는 상위 클래스의 메서드를 재정의할 수 있으며, 이는 다형성을 구현하는 기반이 됩니다.

class Shape {
    public double calculateArea() {
        return 0;
    }
}

class Rectangle extends Shape {
    private double width, height;
    
    public Rectangle(double w, double h) {
        this.width = w;
        this.height = h;
    }
    
    @Override
    public double calculateArea() {
        return width * height;
    }
}

class Circle extends Shape {
    private double radius;
    
    public Circle(double r) {
        this.radius = r;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

super 키워드 활용

super 키워드는 부모 클래스의 멤버에 접근하거나 생성자를 호출할 때 사용됩니다.

class Electronics {
    protected String model;
    
    public Electronics(String model) {
        this.model = model;
    }
    
    public void powerOn() {
        System.out.println("기본 전원 켜기");
    }
}

class Smartphone extends Electronics {
    private int batteryLevel;
    
    public Smartphone(String model, int battery) {
        super(model);
        this.batteryLevel = battery;
    }
    
    @Override
    public void powerOn() {
        super.powerOn();
        System.out.println(model + " 스마트폰 전원 켜짐 (배터리: " + batteryLevel + "%)");
    }
}

인터페이스를 통한 다중 상속 효과

자바는 클래스 단일 상속만 지원하지만, 인터페이스를 통해 유사한 효과를 얻을 수 있습니다.

interface Flyable {
    void fly();
}

interface Swimmable {
    void swim();
}

class Duck extends Animal implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("오리가 날아갑니다.");
    }
    
    @Override
    public void swim() {
        System.out.println("오리가 수영합니다.");
    }
}

final 키워드와 상속 제한

final로 선언된 클래스는 상속이 불가능하며, 메서드는 오버라이딩이 금지됩니다.

final class ImmutableConfig {
    private final String version;
    
    public ImmutableConfig(String ver) {
        this.version = ver;
    }
    
    public final String getVersion() {
        return version;
    }
}

// class CustomConfig extends ImmutableConfig {} // 컴파일 에러

추상 클래스 상속

추상 클래스는 인스턴스화할 수 없지만, 공통적인 구조를 하위 클래스에게 제공합니다.

abstract class GameCharacter {
    protected int health;
    protected String name;
    
    public GameCharacter(String characterName) {
        this.name = characterName;
        this.health = 100;
    }
    
    public abstract void specialAttack();
    
    public void displayStatus() {
        System.out.println(name + " 체력: " + health);
    }
}

class Warrior extends GameCharacter {
    public Warrior(String name) {
        super(name);
    }
    
    @Override
    public void specialAttack() {
        System.out.println(name + "이(가) 강력한 베기 공격을 합니다!");
    }
}

접근 제어와 상속

상속 관계에서 접근 제어자의 영향은 다음과 같습니다:

  • private: 하위 클래스에서 접근 불가
  • protected: 같은 패키지 또는 하위 클래스에서 접근 가능
  • public: 모든 위치에서 접근 가능
  • 패키지-private(default): 같은 패키지 내에서만 접근 가능
class BaseComponent {
    private String secretKey = "private-data";
    protected String internalId = "protected-data";
    public String publicName = "public-data";
}

class ExtendedComponent extends BaseComponent {
    public void accessTest() {
        // System.out.println(secretKey);    // 컴파일 에러
        System.out.println(internalId);      // 접근 가능
        System.out.println(publicName);      // 접근 가능
    }
}

다형성과 타입 변환

상속을 통해 업캐스팅과 다운캐스팅이 가능해지며, 이는 다형성을 실현하는 핵심 요소입니다.

Shape[] shapes = {
    new Rectangle(5.0, 3.0),
    new Circle(2.5),
    new Rectangle(4.0, 6.0)
};

for (Shape shape : shapes) {
    System.out.println("면적: " + shape.calculateArea());
}

태그: java OOP Inheritance Polymorphism abstraction

7월 14일 16:04에 게시됨