iza*_*iel 28 java annotations javafx
我想知道JavaFX 8中@NamedArg注释的用例是什么
javadoc没有给我们更多细节,Javadoc:Annotation提供有关参数名称的信息.
互联网上没有更多信息,文档和示例.
也许有人可以帮忙?
问候.
Jam*_*s_D 49
该@NamedArg注释允许的FXMLLoader实例不具有零参数的构造函数的类.
技术背景:
在FXMLLoader使用反射创建对象.通常,如果使用对应于带有不带参数的构造函数的类的标记,则通过调用从该类创建一个对象,该对象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....
}
Run Code Online (Sandbox Code Playgroud)
在FXML中,我们可能会尝试创建Person如下:
<Person firstName="Jacob" lastName="Smith"/>
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为FXML加载器不能保证Person类的运行时表示保留关于哪个构造函数参数是firstName哪个以及哪个是哪个的信息lastName.
历史背景
Java 2.2定义了与每个控件对应的"Builder"类.这些构建器类遵循标准构建器模式.当FXMLLoader遇到引用没有零参数构造函数的类的标记时,它将使用相应的构建器来创建实例.
不幸的是,构建器类的实现存在缺陷,它们在JavaFX 8中已被弃用,并将在更高版本(可能是JavaFX 9)中删除.这给了一个问题FXMLLoader,它不再需要构建器类来依赖实例化没有零参数构造函数的类.一个真实的例子是Color类,它没有零参数构造函数,并且将删除它的构建器类.
@NamedArgs
解决此问题的方法是引入一个注释,用于在运行时保留方法(或构造函数)参数的名称.通过反射,我们可以查询构造函数/方法的参数列表,并获取每个参数的类型(但不是名称).也可以查询每个参数的任何注释,并获取这些注释的值.因此,@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); }
}
Run Code Online (Sandbox Code Playgroud)
如果您尝试使用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" />
Run Code Online (Sandbox Code Playgroud)
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());
}
}
Run Code Online (Sandbox Code Playgroud)
那么你在运行时看到一个错误:
Caused by: java.lang.NoSuchMethodException: application.Person.<init>()
Run Code Online (Sandbox Code Playgroud)
表明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); }
}
Run Code Online (Sandbox Code Playgroud)
这将允许根据FXMLLoader需要加载类.
请注意,您还可以通过定义构建器类来解决此问题,并且这也适用于JavaFX 2.0及更高版本.JavaFX团队决定(可能是正确的)使用这种方法的方式不会受到构建器初始实现中存在的错误的影响,这会给框架的代码库增加太多的膨胀.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
显然,如果您使用的是JavaFX 8,那么构造函数注释方法就更少了.
参考文献:
@NamedArg)| 归档时间: |
|
| 查看次数: |
4667 次 |
| 最近记录: |