[java] 생성자에서 super () 전에 계산을 수행 할 수 있습니까?

TextBox 개체를 인수로 사용하는 단일 인수 생성자가있는 Base 클래스가 있다고 가정합니다. 다음 형식의 Simple 클래스가있는 경우 :

public class Simple extends Base {
  public Simple(){
    TextBox t = new TextBox();
    super(t);
    //wouldn't it be nice if I could do things with t down here?
  }
}

super에 대한 호출이 생성자의 첫 번째 호출이어야한다는 오류가 표시됩니다. 그러나 이상하게도 나는 이것을 할 수 있습니다.

public class Simple extends Base {
  public Simple(){
    super(new TextBox());
  }
}

이것이 허용되지만 첫 번째 예는 허용되지 않는 이유는 무엇입니까? 먼저 하위 클래스를 설정해야하고 수퍼 생성자가 호출되기 전에 개체 변수가 인스턴스화되지 않도록해야한다는 것을 이해할 수 있습니다. 하지만 t는 분명히 메서드 (로컬) 변수이므로 허용하지 않는 이유는 무엇입니까?

이 제한을 피할 수있는 방법이 있습니까? super를 호출하기 전에 생성 할 수 있지만 생성자를 입력 한 후에 구성 할 수있는 변수를 유지하는 안전하고 좋은 방법이 있습니까? 또는 더 일반적으로 super가 실제로 호출되기 전에 계산을 수행 할 수 있지만 생성자 내에서 수행 할 수 있습니까?

감사합니다.



답변

예, 간단한 사례에 대한 해결 방법이 있습니다. TextBox인수로 사용하는 개인 생성자를 만들고 공용 생성자에서 호출 할 수 있습니다.

public class Simple extends Base {
    private Simple(TextBox t) {
        super(t);
        // continue doing stuff with t here
    }

    public Simple() {
        this(new TextBox());
    }
}

더 복잡한 작업의 경우 팩토리 또는 정적 팩토리 메서드를 사용해야합니다.


답변

슈퍼 호출 전에 계산에 동일한 문제가있었습니다. 때로는 전화하기 전에 몇 가지 조건을 확인하고 싶을 때super() . 예를 들어 생성시 많은 리소스를 사용하는 클래스가 있습니다. 하위 클래스는 추가 데이터를 원하며 수퍼 생성자를 호출하기 전에 먼저 데이터를 확인하려고 할 수 있습니다. 이 문제를 해결하는 간단한 방법이 있습니다. 약간 이상하게 보일 수 있지만 잘 작동합니다.

슈퍼 생성자의 인수를 반환하고 내부에서 확인하는 클래스 내부의 비공개 정적 메서드를 사용합니다.

public class Simple extends Base {
  public Simple(){
    super(createTextBox());
  }

  private static TextBox createTextBox() {
    TextBox t = new TextBox();
    t.doSomething();
    // ... or more
    return t;
  }
}


답변

되어 필요한 슈퍼 클래스가 안정적으로 구축되어 있는지 확인하기 위해 언어에 의해 처음 . 특히 “생성자가 명시 적으로 수퍼 클래스 생성자를 호출하지 않으면 Java 컴파일러는 수퍼 클래스의 인수가없는 생성자에 대한 호출을 자동으로 삽입합니다.”

귀하의 예에서 수퍼 클래스는 t생성 시점 의 상태에 의존 할 수 있습니다 . 나중에 언제든지 사본을 요청할 수 있습니다.

여기여기에 광범위한 논의가 있습니다 .


답변

더 복잡한 논리를 포함 할 수있는 정적 공급자 람다를 정의 할 수 있습니다.

public class MyClass {

    private static Supplier<MyType> myTypeSupplier = () -> {
        return new MyType();
    };

    public MyClass() {
        super(clientConfig, myTypeSupplier.get());
    }
}


답변

두 번째 예제는 허용되지만 첫 번째 예제는 허용되지 않는 이유는 언어를 깔끔하게 유지하고 이상한 규칙을 도입하지 않을 가능성이 높습니다.

super가 호출되기 전에 코드가 실행되도록 허용하는 것은 초기화되어야했지만 아직되지 않은 것들을 망칠 수 있기 때문에 위험 할 것입니다. 기본적으로 super 자체에 대한 호출에서 많은 작업을 수행 할 수 있다고 생각합니다 (예 : 생성자로 이동해야하는 일부 항목을 계산하기위한 정적 메서드 호출). 그러나 그렇지 않은 경우에는 아무것도 사용할 수 없습니다. -아직 완전하게 만들어진 물체는 좋은 것입니다.


답변

이것이 자바가 작동하는 방식입니다. :-)이 방식으로 선택된 이유가 있습니다. super를 호출하기 전에 로컬에서 계산을 수행 할 수 없다는 것은 참 이상 할 수 있지만 Java에서는 먼저 객체를 할당해야하므로 실수로 수정하기 전에 모든 필드가 올바르게 초기화되도록 Object까지 계속 이동해야합니다. 그들.

귀하의 경우에는 대부분의 경우 super ()에 부여한 매개 변수에 액세스 할 수있는 게터가 있습니다. 따라서 이것을 사용합니다.

super (new TextBox ());
최종 텍스트 상자 상자 = getWidget ();
... 당신의 일을 ...


답변

이것은 추가 개체를 만들고 추가 클래스, 필드, 메서드 등을 만들지 않고도 수정할 수있는 내 솔루션입니다.

class TextBox {

}

class Base {

    public Base(TextBox textBox) {

    }
}

public class Simple extends Base {

    public Simple() {
        super(((Supplier<TextBox>) () -> {
            var textBox = new TextBox();
            //some logic with text box
            return textBox;
        }).get());
    }
}