如何避免为 java class 中的每个字段调用 this.field

How to avoid calling this.field for every field in a java class

有没有办法避免为 class 中的每个字段调用 this.field?

public class Test {
    private String name;
    private String email;

    public Test(String name, String email) {
        // I want to avoid this
        this.name = name;
        this.email = email;
    }

    public Test(Test test) {
        // Something like this would be perfect, setting both name and email to test
        this(test);
    }
}

抱歉,避免这种情况的唯一方法是为构造函数参数和 class 字段使用不同的名称。

    public Test(String _name, String _email) {
        // I want to avoid this
        name = _name;
        email = _email;
    }

也就是说,使用 Java 16+ 的记录语法可能会更好。

只有在名称冲突的情况下才需要使用 this 来解决歧义。

像我这样的一些程序员喜欢经常使用 this. 前缀,而其他人只在必要时才使用。

有关如何避免命名冲突的示例,请参阅

使用IDE,卢克

您的 IDE 将生成构造函数、访问器 (getters/setters)、equals & hashCodetoString 等。所以你不需要输入 this.;让机器打字。

使用自定义设置来控制 IDE 是否包含或省略 this. 前缀。

record

您可能有兴趣使用 records 功能,这是 Java 16+ 中的新功能。记录是编写 class 的一种简短方法,其主要目的是透明且不可变地传递数据。

对于一条记录,默认情况下,编译器会隐式写入构造函数、getter、equals & hashCodetoString。隐式创建的构造函数代表您填充每个成员字段。您编写了该代码的 none。

这是您的 整个 示例 class 写成记录。不需要 this。您的所有成员字段都是自动分配的。

public record Test ( String name , String email ) {}

谨慎使用记录。他们发明的原因是 而不是 编写更少的代码。原因是提供一种透明传输不可变数据的显式机制,academic-speak 中的“名义元组”。更少的样板代码只是一个很好的 side-effect。我强烈建议阅读 JEP 395 以获得更多解释。


提示:您可以将本答案的两点结合起来。让您的 IDE 从记录开始生成 full-blown class。

  1. 写一条记录,在括号中列出您的所有会员字段。
  2. 调用您的 IDE 将 record 转换为 class

瞧,你有一个完整的 class,其中包含构造函数、访问器、equalshashCode,以及 toString,所有这些都由你以最少的输入量写出.

例如,在 IntelliJ 2022 中,从 light-bulb 图标菜单中选择 将记录转换为 class 会变成:

public record Test ( String name , String email ) {}

…进入这个:

package work.basil.example.recs;

import java.util.Objects;

public final class Test
{
    private final String name;
    private final String email;

    public Test ( String name , String email )
    {
        this.name = name;
        this.email = email;
    }

    public String name ( ) { return name; }

    public String email ( ) { return email; }

    @Override
    public boolean equals ( Object obj )
    {
        if ( obj == this ) { return true; }
        if ( obj == null || obj.getClass() != this.getClass() ) { return false; }
        var that = ( Test ) obj;
        return Objects.equals( this.name , that.name ) &&
                Objects.equals( this.email , that.email );
    }

    @Override
    public int hashCode ( )
    {
        return Objects.hash( name , email );
    }

    @Override
    public String toString ( )
    {
        return "Test[" +
                "name=" + name + ", " +
                "email=" + email + ']';
    }
}

警告:该结果可能不是默认值。我可能更改了 IntelliJ 中的设置。

按照建议,使用记录是最简单的方法:

public record Test (String name, String email) {
}

这就是您所需要的。你会得到什么:

  • 接受所有参数的构造函数,顺序与字段列表相同
  • 每个字段的方法。这 而不是 get 开头。在这种情况下,方法是 name()email().
  • equalshashCodetoString 使用所有字段的实现。

不需要复制构造函数,因为每个字段都自动为 final。


如果需要,您可以添加额外的构造函数。但是,它们必须 委托给自动生成的构造函数,因为这是设置字段的构造函数。添加其他实用程序方法也可以。

如果需要,您可以向生成的构造函数添加验证。有一种特殊语法允许您省略所有字段名称:

public record Test (String name, String email) {
    public Test {
        Objects.requireNonNull(name);
        Objects.requireNonNull(email);
    }
}

作业已为您完成,您也无需输入。

你每次都需要this.x,如果有2个或更多的变量,称为x并且你想调用属性变量x。 使用 this 关键字,指向 class.

的已创建实例(对象)的属性变量

可能有一个名为 x 的属性和一个也称为 x 的局部变量。