본문 바로가기
Tech Interview 정리

Java의 상속에 대해서 이것 저것 정리

by kkkdh 2023. 8. 2.
728x90

상속의 의미

Java에서 extends라는 예약어로 상속을 표현한다는 것은 알고 계시는 분들이 많을 것 같습니다.

 

그렇다면, 상속은 무엇을 의미할까요??

 

Java에서 상속이 의미하는 바는 extends (확장하다)라는 예약어에서 알 수 있듯이 확장의 의미를 갖습니다.

 

접근 제어자가 public, protected로 설정되어 있는 부모 클래스의 멤버를 자식 클래스가 기본적으로 물려받고, 이에 더해서 추가적인 기능을 자식 클래스가 구현하니 확장의 개념이 되는 것입니다.

 

접근 제어자란??
Java에는 4가지의 접근 제어자 public, protected, package-private, private가 존재합니다.
public 쪽으로 갈수록 공개되는 접근 제어자이며, private 쪽으로 갈수록 외부에 공개가 제한되는 접근 제어자입니다.

package-private는 아무 접근 제어자도 명시하지 않았을 때 설정되는 접근 제어자로 같은 패키지 내에서의 접근만을 허용합니다.
 

Controlling Access to Members of a Class (The Java™ Tutorials > Learning the Java Language > Classes and O

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

Java access modifier 접근 범위

 

상속을 통해서 객체 지향의 특징 중 하나인 다형성을 충족할 수 있습니다.

 

다형성이 어떻게 충족되는지 여기까지만 정리해서는 알 수 없고, overriding이라는 개념과 부모 클래스와 자식 클래스의 형변환 관계에 대해서 더 이해를 해봐야 합니다.


Overriding (오버라이딩)에 대해서

먼저 오버라이딩부터 알아보겠습니다.

 

백문이 불어일타라고 코드로 알아보겠습니다.

public class Parent {
	public void printName() {
    	System.out.println("Class - Parent");
    }
}

class Child extends Parent {
	public void printName() {
    	System.out.println("Class - Child");
    }
}

 

Parent.java 파일에 위와 같이 코드를 작성하는 상황을 가정하고, 다음과 같이 main method를 실행한다고 해봅시다.

 

package ...;

public class Test {
	public static void main(String[] args) {
    	Parent child = new Child();
        child.printName();
    }
}

// ---- result ---- //
Class - child

(간단한 예시이므로 package 정보 작성은 간단히 하고, import는 생략했습니다..)

 

실행 결과 Child class에 printName method를 Parent type으로 선언한 후에 실행했음에도 Child class에 선언된 printName method의 내용대로 실행되었습니다.

 

사실 여기에는 상속 관계에서의 형변환 개념과 overriding 개념이 포함되었습니다.

 

코드 자체의 형태와 실행 결과를 보면 알 수 있듯, 오버라이딩이라는 것은 부모 클래스에서 이미 선언한 method와 동일한 signature로 선언하되, 다른 로직으로 구현하여 자식 클래스별로 개별화된 method 실행이 가능하도록 하는 개념입니다.

 

 

오버라이딩의 규칙 몇 가지

  • 부모 클래스와 같은 signature를 가져야 한다.
  • 부모 클래스에서 overriding 하는 method의 접근 제어자는 다를 수 있다.
  • 다만, 자식 클래스에서의 접근 제어자는 확장만 가능 (protected -> public, private -> protected)
  • overriding 된 method는 부모 클래스와 동일한 return type을 가져야 한다.

 

 

이쯤 되면, 오버로딩과 오버라이딩을 헷갈릴 수도 있으나 둘은 명확히 다른 개념입니다.

지금 읽고 있는 "자바의 신 vol1" 책에서는 이 둘을 오버로딩은 확장, 오버라이딩은 덮어 씀 (부모의 것을 복제하고 필요한 경우 덮어씌우는 개념이라 그런 것 같다)라고 표현하고 있는데, 괜찮은 표현인 것 같습니다.

참조 자료형의 형 변환

아까 넘어갔던 상속 관계에서의 형 변환도 간단히 정리하면 다음과 같습니다. (정확하게는 참조 자료형의 형 변환)

 

public class Parent {
	public Parent() {}
    
    public Parent(String name) {}
    
    public void printName() {
    	System.out.println("printName() - Parent");
    }
}

public class Child extends Parent {
	public Child() {}
    public Child(String name) {}
    
    public void printName() {
    	System.out.println("printName() - Child");
    }
    public void printAge() {
    	System.out.println("printAge() - 18 month");
    }
}

 

두 클래스는 각각 다른 파일에 들어가야 하지만, 편의상 하나의 코드로 작성해 봤습니다.

 

코드는 Parent, Child class에 대한 것이며, Child는 Parent class를 상속받고 있습니다.

 

참조형 타입의 형 변환은 다음과 같은 케이스들이 가능합니다.

 

Parent child1 = new Child();
Child child2 = new Child();

Parent parent = new Parent();
Child child3 = (Child) parent;

 

자식 클래스는 부모 클래스인 Parent class type으로 암묵적 형 변환을 통해 대입 가능하지만, 부모 클래스인 Parent type 객체가 Child type 변수에 담기기 위해서는 명시적 형 변환이 필요합니다.

 

이를 Java 기본 자료형 타입의 형 변환 개념에 대입해 봤을 때,

  • 부모 클래스 → 자식 클래스: Narrowing Casting
  • 자식 클래스 → 부모 클래스: Widening Casting

과 같이 취급되고 있음을 이해할 수 있었습니다. 

 

이에 따라 부모에서 자식으로의 형 변환은 명시적 형 변환이 필요한 반면, 자식에서 부모로의 형 변환은 암묵적 형 변환이 가능한 것이죠

 

Java 기본 자료형의 형 변환 (narrowing, widening casting)에 대해 잘 모르시는 분들은 아래와 같은 글을 참고하시면 좋을 것 같습니다.

 

 

https://www.w3schools.com/java/java_type_casting.asp

 

Java Type Casting

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 


마지막으로 다형성 (Polymorphism)에 대해서 😀

다형성은 어느 자료를 보면서 공부를 해도 객체 지향적 개발에서 가장 중요한 특성 중 하나로 꼽히곤 합니다.

 

학부 시절 처음 개념을 들었던 이후로 어느 정도 이해가 된 것 같기는 하나, 글로써 명확히 정리한 적은 없는 것 같아 이번 글에서 앞서 정리했던 개념들을 바탕으로 정리해보려 합니다.

 

 

 

"다형성"이라는 말의 풀이는 "형태가 다양함"을 의미합니다.

 

이제 다형성이라는 개념과 상속, 참조형의 형 변환, overriding, overloading 등의 개념들이 엮이는 이유를 어느 정도 유추할 수 있을 것 같습니다.

 

상속을 통해 부모 클래스와 닮은 여러 가지의 자식 클래스를 만들어내고, overriding, overloading을 통해 동일하거나 유사한 signature를 갖는 method를 확장하고 개별화할 수 있습니다.

 

 

 

미자막으로 참조형의 형 변환으로 상속 관계에 놓여있는 자식 클래스를 부모 클래스 타입으로 선언 및 관리하지만, 객체의 멤버들을 호출할 때 실제 실행되는 것은 객체의 실제 타입 (자식 클래스)에 선언된 내용을 바탕으로 실행됩니다.

 

"자바의 신" 책에서는 다형성을 "형 변환을 하더라도, 실제 호출되는 것은 원래 객체에 있는 메서드가 호출된다"라는 문장으로 설명하고 있습니다.

 

저는 이 말을 "부모 클래스(또는 인터페이스)라는 공통 타입에 의존한 코드 작성을 하지만, 실제 실행되는 코드는 부모 클래스를 상속받은 자식 클래스 객체 타입에 따라 개별화된 코드가 실행될 수 있는 특성."이라는 느낌으로 이해했습니다.

 

그러니깐, 공통적인 형태의 코드(부모)를 실행하더라도 여러 가지 형태의 구현에 따라 다양한 실행 결과(다양한 형태)를 가질 수 있어서 다형성이라는 말로 표현하는 게 아닐까? 생각했습니다.

 

 

 

Spring framework를 사용해서 DI(Dependency Injection)를 통해 순수 자바만으로는 충족할 수 없었던 객체 지향적 개발을 돕는다는 설명을 공부를 하며 많이 들었는데,

 

결국 DI도 인터페이스에 의존하고 있더라도 spring container에 의해 구현체가 주입을 돕는 것이고 이는 결국 다형성과 연결되는 이야기 이므로, 왜 다형성을 그렇게 중요하게 생각하는지 이해할 수 있었던 것 같습니다.

728x90

댓글