Setter在Java中完成了最后的决赛

Koe*_*nie 7 java setter final const

我一直在用java编程,最近我开始学习一些c ++.

在C++中,将setter params设置为const是常规的,为什么我们在java中看不到这一点?

我的意思是创建一个像这样的setter有任何缺点:

public void setObject(final Object o){ this.o=o; }
Run Code Online (Sandbox Code Playgroud)

VS

public void setObject(Object o){ this.o=o; }
Run Code Online (Sandbox Code Playgroud)

第一个应该强制Object param o在整个set函数中保持不变,不是吗?

编辑:

最后一个参数将强制执行此操作:

public void setName(String name){ 
     name="Carlos";
     this.name=name; 
}
Run Code Online (Sandbox Code Playgroud)

用户将永远无法设置与"Carlos"不同的名称

Hov*_*els 7

将Java方法参数设置为final是没有什么好处的,因为它不会阻止某人更改方法中的参数引用状态.它所阻止的只是将参数变量重新赋值给其他东西,这对原始引用没有任何作用,它允许在匿名内部类中使用该参数.如果您希望在这种情况下获得真正的安全性,那么您应尽可能使参数类型不可变.


编辑
您发布的:

public void setObject(Object o){ 
     o++; // this does not compile
     this.o=o; 
}
Run Code Online (Sandbox Code Playgroud)

其中混合了原始数字和引用类型.只有o是Integer或其他数字包装类才有意义,即使这样,最终也不会阻止某人创建:

private void setI(final Integer i) {
   this.i = 1 + i;
}
Run Code Online (Sandbox Code Playgroud)

但是上面的代码和上面的代码都不会影响调用代码端的参数对象.


编辑
确定现在你发布了:

public void setName(String name){ 
     name="Carlos";
     this.name=name; 
}
Run Code Online (Sandbox Code Playgroud)

但是有人可以写

public void setName(final String name){ 
     this.name= name + " Carlos"; 
}
Run Code Online (Sandbox Code Playgroud)

这就是危险来临的地方,也是最终无济于事的地方.假设您有一个名为Name的类:

public class Name {
   private String lastName;
   private String firstName;
   public Name(String lastName, String firstName) {
      this.lastName = lastName;
      this.firstName = firstName;
   }
   public String getLastName() {
      return lastName;
   }
   public void setLastName(String lastName) {
      this.lastName = lastName;
   }
   public String getFirstName() {
      return firstName;
   }
   public void setFirstName(String firstName) {
      this.firstName = firstName;
   }
}
Run Code Online (Sandbox Code Playgroud)

然后是一个类,Foo,带有Name字段和setter.这是危险的代码:

class Foo {
   private Name name;

   public void setName(final Name name) {
      name.setFirstName("Carlos");
      this.name = name;
   }
}
Run Code Online (Sandbox Code Playgroud)

因为它不仅改变了字段的状态,它还改变了调用代码中Name引用的状态,而final修饰符对一位没有帮助.解决方案:使名称不可变.

例如,

import java.util.Date;

// class should be declared final
public final class BetterName {
   private String lastName;
   private String firstName;
   private Date dateOfBirth;

   public BetterName(String lastName, String firstName, Date dob) {
      this.lastName = lastName;
      this.firstName = firstName;

      // make and store a private copy of non-immutable reference types
      dateOfBirth = new Date(dob.getTime()); 
   }

   // only getters -- no setters
   public String getLastName() {
      return lastName;
   }

   public String getFirstName() {
      return firstName;
   }

   public Date getDateOfBirth() {
      // return copies of non-immutable fields
      return new Date(dateOfBirth.getTime());
   }
}
Run Code Online (Sandbox Code Playgroud)


Joo*_*gen 5

好的,final不能将参数/变量分配给它。由于Java编译器需要能够确定变量/参数是否实际上是最终的(对于匿名内部类),因此优化不是AFAIK的因素。

C ++具有更大的工具集,而Java尝试减少了更多的工具集。因此,使用C ++ const string&很重要,

  1. 该字符串由指针传递,访问自动取消引用。
  2. 如果实际参数是变量,则变量本身不会更改。
  3. 请注意,可能会有一个转换运算符,用于传递除以外的其他内容const string&

现在的java:

  1. Java不会在堆栈上分配对象,而只会在堆栈上保留原始类型和对象句柄。
  2. Java没有输出参数:传递给方法调用的变量将永远不会更改其立即值。

回到您的问题:

作为Java中的setter,大多数人不会从final参数中受益。最终将是不使用该变量进行第二次分配的合同。

然而:

public final void setXyz(Xz xyz) {
    this.xyz = xyz;
}
Run Code Online (Sandbox Code Playgroud)

更为有用:此方法不能被覆盖,因此可以在构造函数中安全使用。(在构造函数中调用重写方法将处于尚未初始化的子实例的上下文中。)