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

2022-09-01 06:44:45

我想知道JavaFX 8中@NamedArg注释的用例是什么

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

互联网上没有更多的信息,文档,示例。

也许有人可以帮忙?

问候。


答案 1

该批注允许 实例化没有零参数构造函数的类。@NamedArgFXMLLoader

技术背景:

使用反射创建对象。通常,如果使用与构造函数不带参数的类对应的标记,则通过调用 从该类创建对象,这将调用无参数构造函数。FXMLLoaderClass.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中,我们可能会尝试创建如下:Person

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

这不起作用,因为 FXML 加载程序不能保证类的运行时表示形式保留有关哪个构造函数参数是 和 哪个是 .PersonfirstNamelastName

历史背景

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

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

@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); }
}

如果您尝试使用 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" />

主要.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>()

表示 正在寻找一个不带参数的构造函数 ()。FXMLLoaderPerson.<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

请注意,您还可以通过定义生成器类来解决此问题,这也适用于 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);
    }
}

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

引用:


答案 2

推荐