• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    미해결

3. 클래스를 상속받을 때 주의할점 질문

22.05.22 23:17 작성 조회수 653

4

그 Base 와 Derived를 설명 해 주실 때
1. 상위 클래스 생성자가 실행되는 동안 하위 클래스의 프로퍼티 즉 Derived를 인스턴스화 한다는 말은
2. Derived에 있는 number에 값을 집어 넣어준다는 건데
3. 이때 상위 클래스에서 넘버를 호출하게 되면 하위 클래스에 있는 넘버를 가져오잖아요
4. 근데 아직 상위 클래스의 constructor가 먼저 실행된 단계라서 하위 클래스에 number 라는 값에 초기화가 이루어지지 않아서 0 이 나오는 거에요.
 
(3.)을 삽질을 조금 해가며 찾아봤었는데, 제가 이해했는게 맞는지 질문드립니다.
"open 된 부모 클래스의 필드는 사용자가 지정한 값을 무시하고, 기본 값을 할당한다. 이후 자식 클래스에서 같은 이름의 필드를 만들어 사용한다. (쉐도잉)"
그래서 부모 클래스 Base init {..} 안에 open 필드를 사용하면 기본값이 나온다고 이해 했습니다. 제가 이해한 내용이 맞을까요?
 
- - <장문 주의> - -
이런 결론을 내게된 과정은 아래와 같습니다.

자바로 디컴파일을 해보니, 코틀린은 생성자를 여러 개를 역할 나눠 순서대로 사용하더라구요.
 
1, (기본 값) (사용여부를 나타내는 이진수) (기본생성자 마커)
각 매개변수에 넣을 기본 값을 지정. var 로 선언하더라도 동일
public Base() {
this(0, 0, 0, 0, 0, 31,
(DefaultConstructorMarker)null);
}

2. (사용여부를 나타내는 이진수)를 바탕으로 초기화를 하는 생성자
예) 총 5개중에 첫번째, 세번째 변수 사용 => 10100
public Base(int var1, int var2, int var3, int var4,
int
var5, int var6, DefaultConstructorMarker var7) {
// 매개 변수를 5개를 사용해서, 6번째에 사용여부 이진수를 넣음
if ((var6 & 1) != 0) {
var1 = 100;
}

if ((var6 & 2) != 0) {
var2 = -1;
}

if ((var6 & 4) != 0) {
var3 = -11;
}

if ((var6 & 8) != 0) {
var4 = -22;
}

if ((var6 & 16) != 0) {
var5 = -33;
}

this(var1, var2, var3, var4, var5)
 
3. 일반적인 생성자 코드와 init {...} 안의 내용
public Base(int number, int base, int hoho, int hihi, int hehe) {
this.number = number;
this.base = base;
this.hoho = hoho;
this.hihi = hihi;
this.hehe = hehe;
String var6 = "Base Class " + this.base;
System.out.println(var6);
var6 = "B " + this.getNumber();
System.out.println(var6);
}
 
즉 Base 부모 클래스에는 open 한 변수들은 바로 위에 적힌 (3. 생성자)를 통해 기본값이 할당된 상태로 그냥 존재하더라구요.
public class Base {
private final int number; // open 한 매개변수
private final int base; // open 한 매개변수
private final int hoho;
private final int hihi;
private final int hehe;
이후 Derived 자식 클래스에 의해 부모 클래스의 매개변수들이 가려졌었습니다.
public final class Derived extends Base {
private final int number;
private final int derived;

자식 클래스의 초기화 여부와 상관없이 부모클래스 안에서, 부모 필드를 호출했으니 0이 나오게 되는 거더라구요.

이후 자식 객체에서 같은 이름으로 쉐도잉 되는데, 가려졌을 뿐 힙 메모리 상에는 부모클래스의 필드는 그대로 0 이구요.

제가 이해한 내용이 맞을까요?

----------------

혹시 getter 로 접근하는 것과 필드에 직접 접근하는 거에 차이가 있는건가 싶어서, 그것도 확인해보았는데

- 내부에서만 사용하는 경우 getter로 접근하지 않고 직접 필드 접근으로 최적화 되었습니다.

String var3 = "Derived Class " + this.derived;
System.out.println(var3);

- open 을 사용하거나 override된 필드는 getter로 접근하더라구요.

var3 = "D " + this.getNumber();
System.out.println(var3);

근데 최적화의 차이만 있을 뿐, this.number 로 변경되더라도 결과는 다르지 않을 듯 합니다. Base init{..} 은 어차피 부모 필드를 호출하게 되니까요.

답변 1

답변을 작성해보세요.

2

안녕하세요 지원님!! 좋은 질문 너무나도 감사합니다~ 🙏

 

제가 글만으로는 설명이 어려울 수도 있을 것 같아, 영상을 통해 질문에 대한 답변 준비해 보았습니다!!

두괄식으로 말씀드리면 '말씀해주신 것과는 조금 다르게 하위 클래스의 값이 초기화되지 않은 상태로 상위 클래스에서 호출되었기 때문' 입니다!

자세한 내용은 아래의 영상 확인 한 번 부탁드려요~

 

 

영상에서 나오는 코틀린 docs의 주소는 

https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order

입니다!! 해당 paragraph를 읽어보셔도 좋을 것 같아요 :)

 

말씀해주신 것처럼, init block에서 open 프로퍼티를 쓰지 않으면 걱정하지 않아도 될 문제입니다!!

(그와 별개로 동작 원리를 탐구해주시는 모습이 멋있으시네요~!!)

 

너무나도 감사합니다!!!

 

김지원님의 프로필

김지원

질문자

2022.05.23

아 영상보고 바로 이해했습니다 제가 잘못 이해했었네요🥲

친절한 설명 정말 감사합니다🙏
강의는 입문자를 위한 내용이지만, 설명의 깊이는 절대 얕지 않다는 걸 느끼고 갑니다. 좋은 강의 만들어주셔서 감사합니다

아이고 아닙니다~ 이 부분이 저도 처음에 많이 헷갈렸어요..!!

설명을 깊이 있게 하기 위해 노력하고 있었는데, 좋은 말씀 감사합니다!! 큰 힘이 되네요..!
앞으로도 노력하겠습니다. 감사합니다 지원님!! 😊