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

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

提问人:Dr4kk0nnys 提问时间:4/22/2022 更新时间:4/22/2022 访问量:151

问:

有没有办法避免为类中的每个字段调用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);
    }
}
Java 构造函数 this

评论

0赞 Nexevis 4/22/2022
如果你在 Eclipse 上,你可以右键单击你的类,选择 Source => Generate Constructor using Fields,它将创建一个使用所有当前字段填充的构造函数,这样你就不需要手动输入它们了。

答:

3赞 Louis Wasserman 4/22/2022 #1

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

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

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

4赞 Basil Bourque 4/22/2022 #2

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

像我这样的一些程序员更喜欢例行使用前缀,而另一些程序员则只在必要时使用。this.

请参阅 Wasserman 的答案,了解如何避免命名冲突的示例。

使用 IDE,Luke

IDE 将生成构造函数、访问器(getter/setter)、&、等。所以你不需要输入;让机器打字。equalshashCodetoStringthis.

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

record

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

默认情况下,对于记录,编译器隐式写入构造函数 getter 和 。隐式创建的构造函数代表您填充每个成员字段。您无需编写任何代码。equalshashCodetoString

这是作为记录编写时的整个示例类。不需要。所有成员字段都会自动分配。this

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

谨慎使用记录。他们发明的原因不是写更少的代码。原因是提供一种明确的机制来透明地传输不可变数据,用学术术语来说就是“名义元组”。较少的样板编码只是一个不错的副作用。我强烈建议阅读 JEP 395 以获得更多解释。


提示:您可以将本答案的两点结合起来。要求 IDE 从记录开始生成一个完整的类。

  1. 编写一条记录,括号中列出了所有成员字段。
  2. 调用 IDE 以将 .recordclass

瞧,你有一个完整的类,里面有构造函数、访问器和,并且都用你绝对最少的输入写出来。equalshashCodetoString

例如,在 IntelliJ 2022 中,从灯泡图标菜单中选择“将记录转换为类”将变为:

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 中的设置。

1赞 Rob Spoor 4/22/2022 #3

正如建议的那样,使用记录是最简单的方法:

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

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

  • 采用所有参数的构造函数,其顺序与字段列表相同
  • 每个字段的方法。这不是以 开头的。在本例中,方法是 和 。getname()email()
  • equals以及使用所有字段的实现。hashCodetoString

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


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

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

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

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

0赞 David Weber 4/22/2022 #4

如果有 2 个或更多变量(称为 x)并且您想调用属性变量 x,则每次都需要 this.x。 使用 this 关键字指向类的已创建实例(对象)的属性变量。

可能有一个称为 x 的属性,以及一个也称为 x 的局部变量。