Java

명품자바 프로그래밍의 기초: 5장

통촏하여주시옵소서 2024. 8. 14. 13:17

1. 상속(Inheritance) 개요

상속은 객체 지향 프로그래밍의 중요한 개념 중 하나로, 자식 클래스가 부모 클래스의 속성과 메소드를 물려받아 사용할 수 있도록 합니다. 이는 마치 생물학에서 자식이 부모의 유전적 특성을 물려받는 것과 유사합니다. 상속을 사용하면 코드의 재사용성이 높아지고, 중복된 코드를 줄일 수 있어 유지보수가 용이해집니다.

1.1 상속의 장점

  • 클래스의 간결화: 부모 클래스에서 정의된 멤버를 자식 클래스가 물려받으므로, 자식 클래스에서 동일한 특성을 재정의할 필요가 없어 코드가 간결해집니다.
  • 클래스 관리의 용이성: 상속을 통해 클래스들을 계층적으로 분류할 수 있으며, 클래스 구조가 명확해지고 관리가 쉬워집니다.
  • 소프트웨어 생산성 향상: 상속을 통해 기존 클래스의 기능을 확장하거나 새로운 클래스를 빠르게 작성할 수 있어 생산성이 향상됩니다.

2. 자바에서의 상속 구현

자바에서는 extends 키워드를 사용하여 클래스 간의 상속 관계를 정의합니다. 부모 클래스는 "슈퍼 클래스(super class)"라고 불리며, 자식 클래스는 "서브 클래스(sub class)"라고 합니다.

예제:

public class Person {
    // Person 클래스의 코드
}

public class Student extends Person {
    // Student 클래스는 Person 클래스를 상속받음
}

public class StudentWorker extends Student {
    // StudentWorker 클래스는 Student 클래스를 상속받음
}

3. 상속의 특징

  • 단일 상속: 자바에서는 클래스의 다중 상속을 지원하지 않으며, 하나의 클래스는 오직 하나의 부모 클래스만을 상속받을 수 있습니다.
  • 상속의 횟수 제한 없음: 자바에서 상속의 깊이는 제한이 없으며, 여러 단계의 상속이 가능합니다.
  • 최상위 클래스: 자바의 모든 클래스는 암묵적으로 java.lang.Object 클래스를 상속받습니다. 이로 인해 모든 클래스는 Object 클래스의 메소드를 사용할 수 있습니다.

4. 상속과 접근 지정자

자바의 접근 지정자는 public, protected, default, private 네 가지가 있습니다. 이들 접근 지정자는 상속 관계에서 멤버에 대한 접근 범위를 제어합니다.

  • private: 해당 클래스 내부에서만 접근 가능하며, 자식 클래스에서도 접근할 수 없습니다.
  • protected: 같은 패키지 내의 클래스와 다른 패키지에 있는 자식 클래스에서 접근할 수 있습니다.
  • public: 모든 클래스에서 접근 가능합니다.
  • default: 같은 패키지 내의 클래스에서만 접근할 수 있습니다.

5. 서브 클래스와 슈퍼 클래스의 생성자 호출

자바에서 서브 클래스의 객체가 생성될 때, 슈퍼 클래스의 생성자도 함께 호출됩니다. 서브 클래스의 생성자는 항상 슈퍼 클래스의 생성자를 먼저 호출하며, 이는 super() 키워드를 통해 명시적으로 호출할 수 있습니다.

예제:

class Point {
    private int x, y;
    public Point() {
        this.x = 0;
        this.y = 0;
    }
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

class ColorPoint extends Point {
    private String color;
    public ColorPoint(int x, int y, String color) {
        super(x, y); // 슈퍼 클래스의 생성자 호출
        this.color = color;
    }
}

6. 업캐스팅과 다운캐스팅

  • 업캐스팅(Upcasting): 서브 클래스의 객체를 슈퍼 클래스 타입으로 변환하는 것을 업캐스팅이라고 합니다. 업캐스팅된 객체는 슈퍼 클래스의 멤버만 접근할 수 있습니다.
  • Student s = new Student(); Person p = s; // 자동으로 업캐스팅됨
  • 예제:
  • 다운캐스팅(Downcasting): 슈퍼 클래스 타입의 객체를 서브 클래스 타입으로 변환하는 것을 다운캐스팅이라고 합니다. 다운캐스팅은 개발자가 명시적으로 타입 변환을 지정해야 합니다.
  • Person p = new Student(); Student s = (Student) p; // 다운캐스팅
  • 예제:

7. 메소드 오버라이딩(Method Overriding)

메소드 오버라이딩은 서브 클래스에서 슈퍼 클래스의 메소드를 재정의하는 것을 의미합니다. 오버라이딩된 메소드는 슈퍼 클래스의 메소드와 동일한 이름, 매개변수, 리턴 타입을 가져야 하며, 동적 바인딩(dynamic binding)을 통해 실행 시점에서 어떤 메소드가 호출될지 결정됩니다.

예제:

class Shape {
    public void draw() {
        System.out.println("Shape");
    }
}

class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println("Circle");
    }
}

8. 추상 클래스와 인터페이스

  • 추상 클래스: 추상 메소드를 하나 이상 포함하거나, 인스턴스화할 수 없는 클래스를 의미합니다. 추상 클래스는 주로 공통적인 기능을 제공하고, 구체적인 기능은 서브 클래스에서 구현하도록 강제할 때 사용합니다.
  • abstract class Shape { abstract void draw(); } class Circle extends Shape { void draw() { System.out.println("Circle"); } }
  • 예제:
  • 인터페이스: 인터페이스는 클래스가 구현해야 하는 메소드들의 집합을 정의하며, 다중 상속을 지원합니다. 자바 8부터는 디폴트 메소드와 정적 메소드도 포함할 수 있습니다.
  • interface Drawable { void draw(); } class Circle implements Drawable { public void draw() { System.out.println("Circle"); } }
  • 예제:

9. 다형성(Polymorphism)

다형성은 하나의 인터페이스나 슈퍼 클래스에서 여러 가지 형태의 객체를 다룰 수 있는 능력을 의미합니다. 이는 오버라이딩과 업캐스팅을 통해 실현되며, 프로그램의 유연성을 높여줍니다.

예제:

Shape shape = new Circle(); // 업캐스팅
shape.draw(); // Circle의 draw() 메소드가 호출됨