Programing

자바 생성자 상속

lottogame 2020. 5. 21. 08:01
반응형

자바 생성자 상속


Java 생성자가 상속되지 않는 이유가 궁금합니다. 다음과 같은 수업이있을 때 알고 있습니다.

public class Super {

  public Super(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    this.serviceA = serviceA;
    //etc
  } 

}

나중에에서 상속 Super하면 java는 기본 생성자가 정의되어 있지 않다고 불평합니다. 해결책은 분명히 다음과 같습니다.

public class Son extends Super{

  public Son(ServiceA serviceA, ServiceB serviceB, ServiceC serviceC){
    super(serviceA,serviceB,serviceC);
  }

}

이 코드는 DRY와 쓸모없는 (IMHO)가 아니라 반복적입니다. 그래서 질문이 다시 나타납니다.

java가 왜 생성자 상속을 지원하지 않습니까? 이 상속을 허용하지 않으면 어떤 이점이 있습니까?


가정하자 생성자 모든 클래스는 궁극적으로 Object에서 파생 때문에 다음 ... 상속 된 모든 클래스는 매개 변수없는 생성자로 끝날 것입니다. 나쁜 생각입니다. 정확히 무엇을 기대하십니까?

FileInputStream stream = new FileInputStream();

할 것?

이제는 상당히 일반적인 "통과"생성자를 쉽게 만들 수있는 방법이있을 수 있지만 이것이 기본값이라고 생각하지는 않습니다. 서브 클래스를 구성하는 데 필요한 매개 변수는 종종 수퍼 클래스에 필요한 매개 변수와 다릅니다.


Super로부터 물려받을 때 실제로 이런 일이 발생합니다.

public class Son extends Super{

  // If you dont declare a constructor of any type, adefault one will appear.
  public Son(){
    // If you dont call any other constructor in the first line a call to super() will be placed instead.
    super();
  }

}

"Super"에는 기본 생성자가 없으므로 고유 생성자를 호출해야하기 때문입니다.

이제 Java가 왜 생성자 상속을 지원하지 않는지 추측하려고 시도 할 것입니다. 아마도 생성자가 구체적인 인스턴스에 대해 이야기하는 경우에만 의미가 있기 때문에 정의 된 방법을 모르면 무언가의 인스턴스를 작성할 수 없기 때문입니다. (다형성에 의해).


서브 클래스 객체 생성은 수퍼 클래스 생성 방법과 다른 방식으로 수행 될 수 있기 때문입니다. 서브 클래스의 클라이언트가 수퍼 클래스에서 사용 가능한 특정 생성자를 호출하지 못하게 할 수 있습니다.

어리석은 예 :

class Super {
    protected final Number value;
    public Super(Number value){
        this.value = value;
    }
}

class Sub {
    public Sub(){ super(Integer.valueOf(0)); }
    void doSomeStuff(){
        // We know this.value is an Integer, so it's safe to cast.
        doSomethingWithAnInteger((Integer)this.value);
    }
}

// Client code:
Sub s = new Sub(Long.valueOf(666L)): // Devilish invocation of Super constructor!
s.doSomeStuff(); // throws ClassCastException

또는 더 간단합니다.

class Super {
    private final String msg;
    Super(String msg){
        if (msg == null) throw new NullPointerException();
        this.msg = msg;
    }
}
class Sub {
    private final String detail;
    Sub(String msg, String detail){
        super(msg);
        if (detail == null) throw new NullPointerException();
        this.detail = detail;
    }
    void print(){
        // detail is never null, so this method won't fail
        System.out.println(detail.concat(": ").concat(msg));
    }
}
// Client code:
Sub s = new Sub("message"); // Calling Super constructor - detail is never initialized!
s.print(); // throws NullPointerException

이 예제에서 "이 생성자를 상속하고 싶다"또는 "이를 제외한 모든 생성자를 상속하고 싶다"고 선언하는 방법이 필요하다는 것을 알았으며 기본 생성자 상속도 지정해야합니다. 누군가가 슈퍼 클래스에 새로운 생성자를 추가하는 경우를 대비하여 선호도를 설정하거나 "상속"하기를 원한다면 슈퍼 클래스에서 생성자를 반복하도록 요구할 수 있습니다.


Because constructors are an implementation detail - they're not something that a user of an interface/superclass can actually invoke at all. By the time they get an instance, it's already been constructed; and vice-versa, at the time you construct an object there's by definition no variable it's currently assigned to.

Think about what it would mean to force all subclasses to have an inherited constructor. I argue it's clearer to pass the variables in directly than for the class to "magically" have a constructor with a certain number of arguments just because it's parent does.


Constructors are not polymorphic.
When dealing with already constructed classes, you could be dealing with the declared type of the object, or any of its subclasses. That's what inheritance is useful for.
Constructor are always called on the specific type,eg new String(). Hypothetical subclasses have no role in this.


David's answer is correct. I'd like to add that you might be getting a sign from God that your design is messed up, and that "Son" ought not to be a subclass of "Super", but that, instead, Super has some implementation detail best expressed by having the functionality that Son provides, as a strategy of sorts.

EDIT: Jon Skeet's answer is awesomest.


Because a (super)class must have complete control over how it is constructed. If the programmer decides that it doesn't make sense to provide a default (no args) constructor as part of the class's contract, then the compiler should not provide one.


You essentially do inherit the constuctors in the sense that you can simply call super if and when appropriate, it's just that it would be error prone for reasons others have mentioned if it happened by default. The compiler can't presume when it is appropriate and when it isn't.

The job of the compiler is to provide as much flexibility as possible while reducing complexity and risk of unintended side-effects.


I don't know any language where subclasses inherit constructors (but then, I am not much of a programming polyglott).

Here's a discussion about the same question concerning C#. The general consensus seems to be that it would complicate the language, introduce the potential for nasty side effects to changes in a base class, and generally shouldn't be necessary in a good design.


A derived class is not the the same class as its base class and you may or may not care whether any members of the base class are initialized at the time of the construction of the derived class. That is a determination made by the programmer not by the compiler.

참고URL : https://stackoverflow.com/questions/1644317/java-constructor-inheritance

반응형