如何通过 setter 设置最终字段?

How do I set a final field via a setter?

我有以下缩写class:

public class Employee {

    private final float pointPosition;

    public Employee(float pointPosition) {
        this.pointPosition = pointPosition;
    }

}

我想检查构造函数传入的 pointPosition,以确保它不超过 1.0。

我尝试将赋值移动到它自己的私有 setter 方法,该方法执行先决条件检查,但显然这给了我一个错误,因为我在构造函数之外重新分配 final 字段。

我可以将构造函数更改为:

public Employee(float newPointPosition) {
    verifyPointPosition(newPointPosition); //Will throw
    this.pointPosition = pointPosition;
}

但我更愿意用它自己的方法把它全部整齐地包裹起来。

我有哪些选择?

选项 1:不要将其设为最终版本

您可以不将其设为最终状态并将 setter 设为私有。


选项 2:在构造函数中进行检查和设置

这就是您已经展示的内容。


选项 3:骇人听闻的方式

您可以使用反射设置最终变量,但我绝对不推荐这样做,除非您被迫这样做。


我会选择选项 2。如果您担心您的构造函数变得太乱,您可以创建额外的构造函数并将它们设置为私有,例如:

public class MyClass {
    private final float variable;

    public MyClass(float variable) {
        this();
        if(variable < 0.0f || 1.0f < variable)
            throw new IllegalArgumentException("'variable' has to be between 0.0 and 1.0");
        this.variable = variable;
    }

    private MyClass() {
        //Set everything else
    }
}

实际上,这段代码不会编译。

我建议通过将参数段落包装在构造函数的单个方法调用中来做到这一点。

你没有说你想要什么行为,是在值无效时抛出异常,还是只是将其清理为正常值,但无论哪种方式都可以:

public class Employee
  private static final float MAX_POSITION = 1.0f;
  private final float pointPosition;

  public Employee(float pointPosition) {
    this.pointPosition = sanitizePointPosition(pointPosition);
  }

然后你有两个选择:

  1. 抛出异常:

    private float sanitizePointPosition(float pointPosition) {
      if(pointPosition > MAX_POSITION) {
        throw new IllegalArgumentException("Point position must be <= "
                   + MAX_POSITION + ", it was: " + pointPosition);
      }
      return pointPosition;
    }
    
  2. 将值设置为正常值

    private float sanitizePointPosition(float pointPosition) {
      return pointPosition > MAX_POSITION ? MAX_POSITION : pointPosition;
    }