본문 바로가기

멋쟁이사자처럼_부트캠프/Java

[멋쟁이사자처럼 부트캠프 TIL 회고] 백엔드 부트캠프 13기: Java 6일차 생성자, 상속, 오버라이딩과 오버로딩

생성자

클래스의 객체가 생성될 때 호출되는 특별한 메서드로, 객체를 초기화하는 데 사용. 생성자는 클래스 이름과 동일해야 하며, 반환 타입이 없음(예: void조차 쓰지 않음).

 

특징

 

자동 호출:

  • 객체가 생성될 때 자동으로 호출됨.

오버로딩 가능:

  • 생성자도 매개변수의 개수나 타입을 달리하여 여러 개 선언 가능(오버로딩).

기본 생성자:

  • 생성자를 하나도 선언하지 않으면, 컴파일러가 매개변수가 없는 기본 생성자를 자동으로 생성함.

 

역할 

 

객체 초기화:

  • 객체 생성 시 필드를 초기화하거나, 필요한 작업을 수행.

코드 간결화:

  • 초기화 작업을 한 번에 처리하여, 이후 작업에서 간결한 코드 유지.

 

기본 생성자
매개변수 생성자

 

 

생성자 체이닝 (생성자가 다른 생성자를 호출할 수 있다) : 객체 초기화를 단순화하고 중복을 줄이는 데 매우 유용한 패턴.

 

 

생성자가 없는 경우

  • 생성자를 선언하지 않으면, 컴파일러가 매개변수가 없는 기본 생성자를 자동으로 추가함.

생성자와 메서드의 차이

특징 생성자(Constructor) 메서드(Method)
반환 타입 없음 반환 타입 명시 필요 (void 포함)
호출 시점 객체 생성 시 자동 호출 명시적으로 호출해야 함
이름 클래스 이름과 동일 원하는 이름으로 정의 가능
역할 객체 초기화 동작(Behavior) 구현

 

결론

  • 생성자는 객체를 초기화하고, 초기 상태를 설정하는 데 사용됨.
  • 매개변수 생성자와 기본 생성자를 함께 사용하면 유연한 객체 생성이 가능.
  • 객체 지향 프로그래밍에서 객체 생성 및 초기화에 중요한 역할을 담당.

상속

기존 클래스(부모 클래스, 슈퍼 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스, 서브 클래스)에서 물려받아 사용하는 기능,계층적 구조를 설계할 수 있음.

 

상속의 주요 개념

  1. 부모 클래스 (Super Class):
    • 속성과 메서드가 정의되어 있는 기존 클래스.
    • 자식 클래스에 의해 상속받을 수 있음.
  2. 자식 클래스 (Sub Class):
    • 부모 클래스를 확장(extends)하여 새로 정의된 클래스.
    • 부모 클래스의 속성과 메서드를 물려받아 사용할 수 있음.
    • 부모 클래스의 기능을 그대로 사용하거나 재정의(오버라이딩) 가능.
  3. 키워드:
    • extends: 상속을 정의할 때 사용.
    • super: 부모 클래스의 멤버를 참조하거나 호출할 때 사용.

예시

 

상속의 특징

  1. 단일 상속:
    • Java에서는 클래스 간에 단일 상속만 지원함.
    • 하나의 자식 클래스는 하나의 부모 클래스만 상속 가능.
    • 다중 상속을 지원하지 않는 이유: 다이아몬드 문제(모호성 문제) 방지.
  2. Object 클래스:
    • 모든 클래스는 자동으로 Object 클래스를 상속받음.
    • Object 클래스는 toString(), hashCode(), equals()와 같은 메서드를 제공.
  3. 재정의(Overriding):
    • 자식 클래스는 부모 클래스의 메서드를 재정의하여 구현 가능.
    • 재정의 시 @Override 애너테이션을 붙이면 컴파일 타임에 확인 가능.
  4. super 키워드:
    • 부모 클래스의 필드와 메서드를 참조하거나, 부모 클래스의 생성자를 호출할 때 사용.
    • **super()**를 통해 부모 클래스의 생성자를 호출 가능(생성자의 첫 줄에서만 호출 가능).

 

상속의 장점

  1. 다형성(Polymorphism):
    • 상속을 활용하면 부모 클래스를 참조해 자식 클래스의 객체를 다룰 수 있음.
    • 코드의 유연성과 확장성 증가.

상속의 단점

  1. 강한 결합:
    • 부모 클래스와 자식 클래스 간의 강한 의존성 때문에, 부모 클래스를 변경하면 자식 클래스에도 영향을 줄 수 있음.
  2. 복잡성 증가:
    • 상속 계층이 깊어질수록 코드가 복잡해지고 디버깅이 어려워짐.
  3. 오용 가능성:
    • 상속은 "is-a" 관계(자식 클래스는 부모 클래스의 일종이어야 함)에 적합해야 함.
    • 잘못된 관계에서 사용하면 구조가 비논리적일 수 있음.

 

메서드 오버라이딩

자식 클래스에서 부모 클래스의 메서드를 재정의하는 예제.

// 부모 클래스
class Animal {
    void sound() {
        System.out.println("Animals make sounds.");
    }
}

// 자식 클래스
class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Meow!");
    }
}

// 메인 클래스
public class OverrideExample {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.sound(); // "Meow!" 출력 (부모 메서드 재정의)
    }
}

 

 

상속과 메서드 오버라이딩을 활용한 다형성 예제.

// 부모 클래스
class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

// 자식 클래스 1
class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

// 자식 클래스 2
class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a rectangle");
    }
}

// 메인 클래스
public class PolymorphismExample {
    public static void main(String[] args) {
        Shape shape1 = new Circle(); // 부모 타입 참조, 자식 객체 생성
        Shape shape2 = new Rectangle();

        shape1.draw(); // "Drawing a circle" 출력
        shape2.draw(); // "Drawing a rectangle" 출력
    }
}

 

 

추상 클래스와 상속을 활용한 예제.

// 추상 클래스
abstract class Vehicle {
    abstract void run(); // 추상 메서드

    void stop() {
        System.out.println("Vehicle stopped.");
    }
}

// 자식 클래스
class Car extends Vehicle {
    @Override
    void run() {
        System.out.println("Car is running.");
    }
}

// 메인 클래스
public class AbstractExample {
    public static void main(String[] args) {
        Vehicle car = new Car(); // 추상 클래스 타입으로 자식 객체 참조
        car.run(); // "Car is running."
        car.stop(); // "Vehicle stopped."
    }
}

 

상속 vs. 포함(Composition)

  • 상속: "is-a" 관계를 나타냄. (예: Dog is an Animal)
  • 포함: "has-a" 관계를 나타냄. (예: Car has an Engine)

결론

상속은 객체지향 프로그래밍의 핵심 기능으로, 코드 재사용성과 계층적 설계를 지원하며 다형성을 구현할 수 있음. 그러나 남용 시 코드 결합도가 높아지고 유지보수가 어려워질 수 있으므로, 적절한 "is-a" 관계를 기반으로 설계하는 것이 중요함.

 


 

오버라이딩(Overriding)과 오버로딩(Overloading)의 차이점

 

  • 오버라이딩은 부모의 것을 재정의하는 것이고,
  • 오버로딩은 이름은 같지만 다양한 매개변수로 동작을 다르게 하는 것임.

 

 

1. 오버라이딩(Overriding)

상속 관계에서 부모 클래스의 메서드를 자식 클래스에서 재정의하여 사용하는 것.

특징

  • 메서드 이름, 매개변수, 반환 타입이 부모 메서드와 동일해야 함.
  • 자식 클래스에서 부모의 동작을 변경하거나 확장하기 위해 사용.
  • 부모 메서드의 접근 제어자보다 더 restrictive(제한적인) 접근 제어자를 사용할 수 없음. (e.g., 부모가 public이면 자식도 public이어야 함.)
  • @Override 애너테이션을 사용하여 오버라이딩 여부를 명시하면 컴파일러가 확인.

 

2. 오버로딩(Overloading)

같은 이름의 메서드를 여러 개 정의하되, 매개변수의 타입, 개수, 순서를 다르게 설정하는 것.

특징

  • 메서드 이름은 같지만, 매개변수 리스트가 달라야 함.
  • 반환 타입은 상관없음. (메서드 호출 시에는 매개변수 리스트로 구분하기 때문.)
  • 상속과는 무관하게, 같은 클래스 내에서 정의.

 

비교

구분 오버라이딩 (Overriding) 오버로딩 (Overloading)
사용 목적 부모 메서드를 재정의 같은 이름으로 다양한 메서드 정의
상속 여부 반드시 상속 관계에서 사용 상속 관계가 필요 없음
메서드 이름 부모 메서드와 동일 동일
매개변수 부모 메서드와 동일 매개변수의 개수, 타입, 순서가 다름
반환 타입 부모 메서드와 동일 상관없음
애너테이션 사용 @Override 애너테이션 사용 가능 애너테이션 사용 안 함