부모 클래스(Superclass): 상속을 제공하는 클래스
자식 클래스(Subclass): 상속을 받는 클래스, 부모의 멤버를 상속받음
extends 키워드: 상속을 구현할 때 사용
class Animal {
void sound() {
System.out.println("동물이 소리를 냅니다.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("멍멍");
}
}
이 예시에서 Dog는 Animal을 상속받으며, sound() 메서드를 사용할 수 있습니다.
자식 클래스는 부모 클래스의 모든 public, protected 멤버를 상속받는다.
private 멤버는 상속되지만 직접 접근할 수 없다.
자바는 단일 상속만 허용 (하나의 부모 클래스만 상속 가능)
상속받은 메서드는 **오버라이딩(재정의)**이 가능
생성자는 상속되지 않음 (단, 부모 생성자를 호출할 수 있음)
class Animal {
String name = "동물";
}
class Cat extends Animal {
void printName() {
System.out.println(super.name); // 부모 클래스의 name 필드
}
}
class Animal {
Animal(String name) {
System.out.println("Animal 생성자: " + name);
}
}
class Dog extends Animal {
Dog() {
super("강아지"); // 부모 클래스 생성자 호출
}
}
부모 클래스의 메서드를 자식 클래스에서 재정의하는 것
class Animal {
void sound() {
System.out.println("동물이 소리냅니다");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("멍멍");
}
}
오버라이딩 시에는 메서드 이름, 매개변수, 반환형이 부모와 동일해야 하며, @Override 어노테이션을 붙여서 재정의했음을 명시할 수 있습니다.
final 클래스는 상속 불가능
final class Animal { }
// class Dog extends Animal { } // 오류 발생
final 메서드는 오버라이딩 불가능
class Animal {
final void sound() { }
}
class Dog extends Animal {
// void sound() { } // 오류 발생
}
자바의 모든 클래스는 암묵적으로 Object 클래스를 상속합니다. 즉, 별도로 상속을 명시하지 않아도 다음과 같습니다:
class MyClass extends Object {
// Object의 메서드들을 사용할 수 있음
}
Object 클래스는 toString(), equals(), hashCode(), getClass() 등의 메서드를 제공합니다.
접근 제어자 |
같은 클래스 |
같은 패키지 |
자식 클래스 |
전체 외부 |
---|---|---|---|---|
public |
O |
O |
O |
O |
protected |
O |
O |
O |
X |
default |
O |
O |
X |
X |
private |
O |
X |
X |
X |
protected는 상속을 위한 접근 제어자로 자식 클래스에서는 접근 가능하지만, 외부 클래스에서는 불가능합니다.
상속은 **다형성(polymorphism)**과 함께 사용할 때 진정한 객체지향의 힘을 발휘합니다.
class Animal {
void sound() {
System.out.println("소리");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("멍멍");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("야옹");
}
}
public class Main {
public static void main(String[] args) {
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.sound(); // 멍멍
a2.sound(); // 야옹
}
}
class Vehicle {
int speed = 60;
void run() {
System.out.println("Vehicle is running");
}
}
class Car extends Vehicle {
String brand = "Hyundai";
void display() {
System.out.println("Brand: " + brand);
System.out.println("Speed: " + speed); // 부모의 필드 사용
run(); // 부모의 메서드 사용
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.display();
}
}
자바 상속은 코드 재사용성을 높이고 유지보수를 쉽게 만들어 주며, 다형성과 함께 객체지향 프로그래밍의 핵심 요소로 작용합니다. 하지만 무분별한 상속은 오히려 복잡성과 의존성을 증가시킬 수 있으므로, 필요할 때만 적절히 사용하는 것이 좋습니다.