활동/독서

[Do it! 점프 투 자바] 05. 객체 지향 프로그래밍 (상속 / 메서드 오버라이딩과 오버로딩 요약)

ByeongJun 2023. 9. 4. 15:49
반응형

* 본 게시물은 이지스퍼블리싱 [Do it! 점프 투 자바] 서평단 미션 수행 및 학습 목적으로 작성하였습니다.
 

  모든 내용, 디자인, 이미지, 편집 구성의 저작권은 이지스퍼블리싱(주)와 지은이에게 있으며

  학습 목적으로 내용을 재구성하여 작성했음을 밝힙니다. 문제시 삭제하도록 하겠습니다.


 

 

05-05 상속

[TOC] ## 상속 자바에는 자식 클래스가 부모 클래스의 기능을 그대로 물려받을 수 있는 상속(inheritance) 기능이 있다. 예제를 통해서 자바의 상속에 대해서 자세…

wikidocs.net

 

 

 

 

 

상속

 

자바에는 자식 클래스가 부모 클래스의 기능을 그대로 물려받을 수 있는 상속(inheritance) 기능이 있다. 

class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {               // Animal 클래스 상속
}

public class Sample {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("poppy");            // [setName 메서드를 사용하는 이유] 아래 설명 참고
        System.out.println(dog.name);
    }
}

 

Dog 클래스에서 Animal 클래스를 상속하기 위해 extends 키워드를 사용했다. 

setName 메서드를 사용해 name 변수에 'poppy'라는 문자열을 설정하여 그 값을 출력했다. 

 

 dog.setName("poppy");

Dog 클래스에 객체 변수인 name과 setName 메서드를 만들지 않아도

Animal 클래스를 상속했기 때문에 예제에서 보듯이 그대로 사용 가능하다. 

 

 

 

setName 메서드를 사용하는 이유 

  1. 데이터 은닉 (Data Encapsulation)
    - 데이터 은닉은 객체 내부의 데이터나 상태를 외부에서 직접 접근하지 못하도록 보호하는 개념이다. 클래스 내의 데이터는 주로 private 접근 제어자를 사용하여 외부에서 접근할 수 없게 하고, 데이터에 접근하려면 메서드를 통해야 한다. 이것은 클래스의 내부 구현을 외부에 감추고 객체를 안전하게 사용할 수 있게 한다.
  2. 캡슐화 (Encapsulation) 
    - 캡슐화는 데이터와 해당 데이터를 조작하는 메서드를 하나로 묶는 것을 의미한다. 즉, 데이터와 데이터를 다루는 메서드를 함께 묶어서 객체를 형성한다는 의미인데, 이렇게 하면 데이터와 관련된 모든 동작을 객체 내에서 관리할 수 있으며, 객체를 사용하는 코드에서는 객체의 메서드를 호출하여 데이터를 조작할 수 있다.

setName 메서드를 사용하면 클래스 내부의 name 변수에 대한 접근을 외부로부터 제어할 수 있으며, 데이터를 안전하게 설정할 수 있다. 또한 나중에 클래스 내부 구현을 변경할 때 변경 내용을 setName 메서드 내부에 캡슐화할 수 있어서, 외부 코드에 영향을 덜 주면서 유지 보수가 쉬워집니다.

간단히 말해서, setName 메서드를 사용하면 데이터를 안전하게 다룰 수 있고, 클래스의 내부 구현을 숨길 수 있으며, 코드의 유지 보수성을 높일 수 있습니다.

 

 

 

Dog 클래스는 Animal 클래스를 상속했기 때문에 Animal 클래스보다 하위 개념이라고 할 수 있다.

그러므로 '개(Dog)는 동물(Animal)이다' 라고도 표현할 수 있다.

 

자바는 이런 관계를 IS-A 관계라고 표현한다. 

Dog is a Animal (개는 동물이다) 

 

Animal dog = new Dog();   // Dog is Animal
Dog dog = new Animal();   // 컴파일 오류 발생

IS-A 관계 (상속 관계) 경우 자식 클래스의 객체는 부모 클래스의 자료형인 것처럼 사용할 수 있다. 

 

 

 

 

 

메서드 오버라이딩 (Overriding)

 

Animal, Dog, HouseDog 클래스를 정의하고 

HouseDog 객체를 생성한 다음  HouseDog houseDog = new HouseDog(); 
setName 메서드로 이름을 지정한 뒤  houseDog.setName("happy"); 
sleep 메서드를 호출해   houseDog.sleep(); 

"happy zzz in house"를 출력한다.

 

 

 

빨간 테두리로 표시된 두 클래스 중에 호출되는 것은 HouseDog 클래스의 sleep 메서드이다. 

 

부모 클래스의 메서드를 자식 클래스가 동일한 형태로 또다시 구현하는 행위를 

메서드 오버라이딩 (method overriding) 이라고 한다.

 

말 그대로 '메서드 덮어쓰기' 라고 할 수 있다.

 

 

부모님으로부터 가게(클래스)를 물려받아 새로운 메뉴(메서드)를 추가하거나 비유하는 것으로

객체 지향 프로그래밍에서 상속과 다형성을 구현하는 메서드 오버라이딩을 설명할 수 있다. 

 

아니면 오버라이딩이니까 오토바이를 자식에게 물려준다고 이해하면 어떨까..요   원래 이렇게 해야 기억에 잘 남는다

 

 

 

  1. 부모 클래스 (상위 클래스): 부모님으로부터 가게를 물려받은 클래스로 일반적인 동작, 메뉴를 가지고 있을 수 있다.
  2. 자식 클래스 (하위 클래스): 자식이 부모로부터 가게를 물려받은 후, 새로운 메뉴를 추가하거나 기존 메뉴를 변경할 수 있는 클래스. 이 클래스는 부모 클래스의 메서드를 오버라이딩하여 새로운 동작을 제공할 수 있다.
  3. 메서드 오버라이딩 (Method Overriding): 자식 클래스에서 부모 클래스로부터 상속받은 메서드의 내용을 변경하거나 확장하는 것으로, 자식 클래스에서 새로운 구현을 제공하고 부모 클래스의 동작을 재정의한다.
  4. 새로운 기능 추가: 자식 클래스는 부모 클래스에서 상속받은 메서드를 확장하여 새로운 기능을 추가할 수 있다.
    새로운 메뉴 항목을 메뉴에 추가하는 것과 유사하다고 볼 수 있다.
  5. 동작 변경: 자식 클래스는 부모 클래스에서 상속받은 메서드를 오버라이딩하여 동작을 변경할 수 있다.
    메뉴 항목의 조리 방법을 변경하는 것과 유사하다.

 

 

 

 

 

메서드 오버로딩 (method overloading)

 

이상한 오토바이 사진까지 가져오면서(?) 오버라이딩을 설명했다면 

같은 이름의 메소드를 중복하여 정의하는 메서드 오버로딩 (Overloading) 차례가 왔다. 

 

자바에서는 원래 한 클래스 내에 같은 이름의 메서드를 둘 이상 가질 수 없지만, 

매개변수의 개수나 타입을 다르게 하면 하나의 이름으로 메서드를 작성할 수 있다. 

 

생소하다고 생각이 들면 메서드 오버로딩의 가장 대표적인 예시인 println() 메서드를 생각해보자. 

 

 

 

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + " zzz");
    }
}

class HouseDog extends Dog {
    void sleep() {
        System.out.println(this.name + " zzz in house");
    }
}

이미 sleep이라는 메서드가 있지만 동일한 이름의 메서드를 또 생성할 수 있다. 

단, 메서드의 입력 항목이 다를 경우에만 가능하다. 

 

void sleep(int hour) {
    System.out.println(this.name+" zzz in house for " + hour + " hours");
}

새로 만든 sleep 메서드는 입력 항목으로 hour라는 int 자료형이 추가됐다.

 

 

 

 

 

class Calculator {
    int add(int a, int b) {                  // int
        return a + b;
    }

    double add(double a, double b) {         // double
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        
        int result1 = calculator.add(5, 10);            // int 타입 매개변수 호출
        double result2 = calculator.add(3.5, 2.7);      // double 타입 매개변수 호출
        
        System.out.println("Result 1: " + result1);
        System.out.println("Result 2: " + result2);
    }
}

 

Calculator 클래스는 add 메서드를 오버로딩하고 있다.

동일한 메서드 이름을 사용해 서로 다른 데이터 유형을 처리하는 예시이다. 

 

메서드 오버로딩 특징
  1. 메서드 이름 동일 : 오버로딩된 메서드들은 모두 동일한 이름을 가진다.
  2. 매개변수 목록 다름 : 오버로딩된 메서드들은 매개변수의 종류, 순서, 또는 개수가 서로 다르다.
  3. 반환 유형은 오버로딩에 영향을 주지 않음
     :
    반환 유형(리턴 타입)만 다른 경우는 오버로딩이 아니다. 매개변수의 차이가 있어야 한다.
더보기

[ 정상 ]

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }
}

 하나는 int, 다른 하나는 double 매개변수를 받고 있어 오버로딩이 정상적으로 동작한다. 

 

 

[ 오류 ]

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(int a, int b) {
        return (double)(a + b);
    }
}

add 메서드가 정의되어 있지만, 매개변수의 타입이 int로 같은 것을 볼 수 있다. 
return 타입(반환 유형)만 다를 뿐이어서 컴파일 오류가 발생한다. 

 method add(int,int) is already defined in class Calculator 

 

동일한시그니처(매개변수의 타입과 개수)를 가진 메서드가 이미 클래스에 정의되어 있다는 
메시지가 표시된다.

 

 

 

메서드 오버로딩 장점
  • 명확한 메서드 호출
     : 메서드 이름이 같기 때문에, 클라이언트 코드는 각각의 오버로딩된 메서드를 구분하지 않고 사용할 수 있다.
  • 메서드 호출 다양성 
     : 서로 다른 타입의 데이터를 다룰 수 있게 해주므로, 메서드 호출 다양성을 제공

 

반응형