자바 객체지향 기본개념 - 다형성 (1)

Vinci·2024년 3월 27일
0

본 자료는 ‘소설같은 자바 2nd Edition’ (최영관 저)을 기반으로 작성하였습니다.

다형성(Polymorphism)

다형성은 객체지향 프로그래밍에서 중요한 개념으로 말 그대로 “많은 형태를 가질 수 있는 특성”을 뜻합니다. 예를 들면, 같은 이름의 메서드가 클래스에 따라 다른 동작을 하게 하는 다형성의 요소 중 하나입니다. 이런 방식은 코드가 변화에 유연하게 그리고 유지보수에 용이하도록 해줍니다.

이제 다형성을 구사하기 사용하는 개념들을 알아보겠습니다.

상속(Inheritance)

상속이란 하위클래스가 상위 클래스의 모든 기능과 특성을 물려받는 개념입니다. 상위 클래스의 기능을 그대로 이어 받아 그 위에 새로운 기능을 추가하여 업그레이드 된 클래스를 만들 수 있는 자바의 강력한 기능입니다.

상속은 extends 키워드를 사용하여 구현할 수 있으며 하나의 클래스는 하나의 상속만 가질 수 있다는 규칙이 있습니다.

그렇다면 하위 클래스는 상위 클래스로 부터 무엇을 물려 받는 걸까요?

  • 상위 클래스의 멤버 변수
  • 생성자를 제외한 상위 클래스의 멤버 메서드

다음 예제를 통해 상속이 어떻게 이루어지는지 알아봅시다.

class Father {

    private int age;
    public String surName;

    public Father() {
        age = 50;
        surName = "Lee";
    }

		public int getAge() {
		        return age;
		}
}

class Son extends Father{
}

public class InheritanceExample {

    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.surName);
    }
}
// 결과값
Lee

아들(하위 클래스)이 아버지(상위 클래스)와 상속관계에 있기 때문에 아버지의 surname을 그대로 사용하고 있음을 볼 수 있습니다.

하지만 여기서 의문점이 하나 생깁니다.

아버지의 생성자를 호출하지 않았는데 어떻게 surname 변수가 “Lee”라는 값을 갖게 된걸까요?

정답은 하위 클래스가 호출되는 동시 상위 클래스의 생성자가 자동으로 먼저 호출되기 때문입니다!

설명하자면, new Son()이 실행되는 즉시 상위 생성자인 Father()가 호출되면서 age와 surname이 초기화 됩니다. 그 다음 하위 생성자인 Son()이 실행을 이어갑니다.

그럼 private 변수인 age도 아들이 아버지처럼 직접 접근할 수 있을지 확인해봅시다.

public class InheritanceExample {

    public static void main(String[] args) {

        Son son = new Son();
        System.out.println(son.age);
    }
}
error: age has private access in Father
        System.out.println(son.age);

사실 컴파일 타임부터 에러가 뜹니다. 다시 말해 private만은 하위 클래스도 직접 접근이 불가능합니다. 그렇기 때문에 접근을 위해서는 다음과 같이 public 메서드를 이용해야합니다(Getter)

public class InheritanceExample {

    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.getAge());
    }
}
// 결과값
50

💡 private VS protected
private이 너무 엄격하다고 느껴진다면,
평소에는 private과 같은 기능을 하지만 상속관계에서는 public과 같은 역할을 하는 protected 키워드를 사용할 수 있습니다!

오버라이딩(Overriding)

오버라이딩이란 상위 클래스의 메서드를 하위 클래스에서 같은 이름으로 재정의했을 때, 해당 메서드 호출 시 하위 클래스에서 재정의한 메서드가 호출되는 것을 말합니다.

다음의 예제를 보면 아버지의 sayMyName() 과 동일한 이름의 메서드를 아들도 가지고 있는 걸 볼 수 있습니다. 과연 아들의 이름으로 호출한 sayMyName() 의 출력결과는 어떻게 나올까요?

class Father {

    public void sayMyName() {
        System.out.println("I'm father");
    }
}

class Son extends Father{

    public void sayMyName() {
        System.out.println("I'm son");
    }
}

public class InheritanceExample {

    public static void main(String[] args) {
        Son son = new Son();
        son.sayMyName();
    }
}
// 결과값
I'm son

보시는 것과 같이 아들의 메서드가 아버지의 메서드를 오버라이딩 즉, 지워버렸습니다. 상속이 개선의 의미에서 사용되기 때문에 상위 클래스의 메서드 대신, 개선 되어있을 것이라 여겨지는 하위 클래스의 메서드를 선택하는 오버라이딩은 상식적이라고 볼 수 있습니다.

References

  • 소설같은 자바 2nd Edition’ (최영관 저)
profile
Chase the Truth!

0개의 댓글