FX 11:基类中的控制器加载

FX 11: Controller loading in Baseclass

从基础 class 将 FXML 注入派生的 FX Class(控制器)有效 - 但为什么呢?

下面的代码确实有效。但我很好奇为什么?

FXML 在抽象 Base class (FXMLPopup) 的构造函数中加载并注入到派生的 class(TestfxmlController)。

我的问题:构建基础 class 时(并注入 fxml),派生的 class 尚未构建。 另外恕我直言,基地不应该对派生 class 有任何了解,对吗?

更进一步的字段,就是被注入的派生中是private的class!因此加载程序必须使其可访问,但在基础中没有@FXML 允许这样做(仅在尚未构建的派生 class 中给出权限 - 好吧,字段不'根本不存在于基地!)。

FXML 仍然正确地注入派生 class - 并且字段实际上是派生 class 中的字段。为什么这样做有效?

基础class:

public abstract class FXMLPopup extends Popup implements Initializable {

    @SuppressWarnings("LeakingThisInConstructor")
    public FXMLPopup(String filename) {
        super();
        final FXMLLoader loader = new FXMLLoader(FXMLLoader.class.getResource(filename));
        //if a controller is set in the fxml, ignor it.
        loader.setControllerFactory(p -> this);
        try {
            this.getContent().add(loader.load());
        } catch (IOException ex) { }
     }
}

派生 class:

public class TestfxmlController extends FXMLPopup {

    @FXML
    private ChoiceBox<String> testChoiceBox;

    public TestfxmlController() {
        super("fxml/testfxml.fxml");
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //works!!!!
        testChoiceBox.getItems().add("test");
    }
}

FXML 代码:

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1" fx:controller="TestfxmlController">
   <children>
      <ChoiceBox fx:id="testChoiceBox" layoutX="113.0" layoutY="160.0" prefWidth="150.0" />
   </children>
</AnchorPane>

我会期待什么?我希望错误多于错误。加载程序在基础 class 中找不到字段并且访问被拒绝.... 但它不知何故 magicaly 完美无瑕。尽管我在这么小的例子中尽可能地违反了一切。我想了解这背后的"magic"...

我想我现在明白了。调用 baseclass 构造函数时已经构造了派生的 class - 只是没有初始化。

所以加载器实际上得到的是派生的class。通过给定的反射,能够 return 来自派生 class 的字段。

有了它,基础 class 就可以初始化派生 class 的字段 - 即使基础 class 没有关于其未来派生的任何信息.它不需要。它通过反射获取该信息(rsp。加载程序)。

它甚至不粗糙,因为派生的 class 实际上是通过反射知道的,因此已知是正确的类型。

所以我现在认为这个通用的 FXML Popup 代码实际上是完全有效的。

虽然这个特定的用例很合理,但就记录的用例而言,FXML 加载器似乎存在缺陷。

原因:如果有人创建了一个从 fxml 加载的控件 - 文件以记录的方式(不是这个用例)并将其作为库分发,则该库的用户可以子 class 它。加载程序现在将注入子 class 而不是它要创建的字段,这会导致控件失败(在这种情况下,库 class 中的字段不会被初始化)。

再说一次:虽然问题中的代码似乎可以可靠地工作,但这种行为记录的用例可能会导致问题。