javaFX 8中@NamedArg注解的目的是什么?

我会知道JavaFX 8中@NamedArg注解的用例是什么

javadoc并没有给我们更多的细节,Javadoc:提供关于参数名称的信息的注释。

没有更多的信息,文件,在互联网上的例子。

也许有人可以帮忙?

问候。

@NamedArg注解允许FXMLLoader实例化一个没有零参数构造函数的类。

技术背景:

FXMLLoader使用reflectionFXMLLoader创build对象。 通常情况下,如果您使用与不带参数的构造函数相对应的类的标签,则通过调用Class.newInstance()来创build一个对象,该类调用无Class.newInstance()构造函数。

如果一个类只能用带参数的构造函数来定义,那么这是有问题的。 主要的问题是Java语言规范不要求在运行时保留参数名(方法或构造函数)。 这意味着FXMLLoader不能确定哪个参数具有给定的名称。

为了使这个具体,假设我们定义一个Person类如下:

 package application; import javafx.beans.NamedArg; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; public class Person { private final StringProperty firstName ; private final StringProperty lastName ; public Person(String firstName, String lastName) { this.firstName = new SimpleStringProperty(this, "firstName", firstName); this.lastName = new SimpleStringProperty(this, "lastName", lastName); } // methods.... } 

在FXML中,我们可能会尝试创build一个Person ,如下所示:

 <Person firstName="Jacob" lastName="Smith"/> 

这是行不通的,因为FXML加载器不能保证Person类的运行时表示保留关于哪个构造器参数是firstName和哪个是lastName

历史背景

Java 2.2定义了与每个控件对应的“Builder”类。 这些构build器类遵循标准构build器模式。 当FXMLLoader遇到引用一个没有零参数构造函数的类的标签时,它将使用相应的构build器来创build实例。

不幸的是,构build器类的实现是有缺陷的, 它们在JavaFX 8中被弃用 ,并且会在更高版本(可能是JavaFX 9)中被删除。 这就给FXMLLoader留下了一个问题, FXMLLoader不再需要构build器类来实例化没有零参数构造器的类。 一个真正的例子是Color类,它没有零参数的构造函数,并将其构build器类删除。

@NamedArgs

解决这个问题的方法是引入一个注释,用于在运行时保留一个方法(或构造函数)参数的名称。 通过reflection,我们可以查询构造函数/方法的参数列表,并获取每个参数的types(而不是名称)。 也可以查询每个参数的任何注释,并获得这些注释的值。 所以@NamedArg注解是专门为了在运行时保留一个参数名而引入的。

例如,使用我们上面介绍的Person类:

 package application; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; public class Person { private final StringProperty firstName ; private final StringProperty lastName ; public Person(String firstName, String lastName) { this.firstName = new SimpleStringProperty(this, "firstName", firstName); this.lastName = new SimpleStringProperty(this, "lastName", lastName); } public final StringProperty firstNameProperty() { return firstName; } public final String getFirstName() { return firstNameProperty().get(); } public final void setFirstName(final String firstName) { firstNameProperty().set(firstName); } public final StringProperty lastNameProperty() { return lastName; } public final String getLastName() { return lastNameProperty().get(); } public final void setLastName(final String lastName) { lastNameProperty().set(lastName); } } 

如果您尝试使用FXML加载这个:

Person.fxml:

 <?xml version="1.0" encoding="UTF-8"?> <?import application.Person?> <Person firstName="Jacob" lastName="Smith" xmlns:fx="http://javafx.com/fxml/1" /> 

Main.java:

 package application; import java.io.IOException; import javafx.fxml.FXMLLoader; public class Main { public static void main(String[] args) throws IOException { Person person = FXMLLoader.load(Main.class.getResource("Person.fxml")); System.out.println(person.getFirstName()+" "+person.getLastName()); } } 

那么你在运行时会看到一个错误:

 Caused by: java.lang.NoSuchMethodException: application.Person.<init>() 

表明FXMLLoader正在寻找一个不带参数的构造函数( Person.<init>() )。

在JavaFX 8中,您可以通过使用@NamedArg批注指定参数的名称来解决问题:

 package application; import javafx.beans.NamedArg; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; public class Person { private final StringProperty firstName ; private final StringProperty lastName ; public Person(@NamedArg("firstName") String firstName, @NamedArg("lastName") String lastName) { this.firstName = new SimpleStringProperty(this, "firstName", firstName); this.lastName = new SimpleStringProperty(this, "lastName", lastName); } public final StringProperty firstNameProperty() { return firstName; } public final String getFirstName() { return firstNameProperty().get(); } public final void setFirstName(final String firstName) { firstNameProperty().set(firstName); } public final StringProperty lastNameProperty() { return lastName; } public final String getLastName() { return lastNameProperty().get(); } public final void setLastName(final String lastName) { lastNameProperty().set(lastName); } } 

这将允许FXMLLoader根据需要加载类。

请注意,您也可以通过定义构build器类来解决该问题,并且这也适用于JavaFX 2.0及更高版本。 JavaFX团队决定(可能是正确的),使用这种方法的方式不会受到构build器初始实现中存在的错误的影响,这会增加框架代码库的膨胀。

 package application; public class PersonBuilder { private String firstName ; private String lastName ; private PersonBuilder() { } public static PersonBuilder create() { return new PersonBuilder(); } public PersonBuilder firstName(String firstName) { this.firstName = firstName ; return this ; } public PersonBuilder lastName(String lastName) { this.lastName = lastName ; return this ; } public Person build() { return new Person(firstName, lastName); } } 

很显然,如果您使用的是JavaFX 8,构造函数注释方法的工作量要less得多。

参考文献:

  • build议贬低build设者
  • 调整请求以添加构造函数注释
  • build造者模式
  • FXML文档 (讨论构build者,但不是@NamedArg
  • 请求将@NamedArgs上的文档添加到“FXML简介”文档中