当创建一个可变类而不使用final时,如
public final class X {...}
而是只使用常规的类声明而没有 final,如
public class X {...}
然后使用静态工厂构造函数,使用私有构造函数,其中所有字段都是私有的,那么我的问题是 -仅声明私有字段而不声明最终字段还不够吗,例如
private double d;
或者/为什么我还要说
private final double d;
我唯一的答案是,我不会错误地在班级内改变任何非最终字段,但是任何人都可以从外部更改吗?
不可变的类意味着在创建该类的实例后无法更改类状态和/或值。使类不可变可以通过多种方式完成;使用final
变量会有所帮助,并且使类本身final
可以通过防止子类可能破坏不可变性规则的子类来提供帮助。
在类上使用final
关键字与在变量上使用它意味着两件完全不同的事情。
将类设置为 final 意味着该类不能被子类化;也就是说,如果你有
public final class X {...}
您无法扩展它
public class Y extends X {...} // Illegal!
类是否为最终与类成员变量是否为最终无关。
将变量设置为final
,无论是static
、类成员变量还是局部(方法或块)变量,都意味着变量在被赋值后无法更改。
您的代码还需要通过任何可用的执行路径为最终变量设置一个值,所以这没关系,因为它总是将"max"设置为某些内容:
...
final int max;
if (parameter) {
max = 100;
} else {
max = 1000;
}
但这会给你一个错误:
...
final int max;
if (parameter) {
max = 100;
}
因为如果"参数"的计算结果为true
,它会设置"max",否则永远不会设置"max"。
这通常在不可变对象的构造函数中完成:
public final class X
{
final int value;
public X(int v)
{
this.value = v; // Now that `value` has been set
// it can never be changed
}
}
将一个类声明为final
并不意味着它的类成员是最终的,所以你的问题"为什么我还要说">是因为final
的这两种用法是不相关的。
请注意,您还可以将方法声明为 final:
public final int getMax() {...}
这意味着不允许子类使用新实现重写此方法。(如果类已经final
,则方法上的final
没有意义,因为不可能有任何子类尝试重写该方法。
无论您是否添加final
,没有人能够触及该类代码之外的这些值。
如果可以的话,最好将它们声明为最终的,因为它确实为编译器提供了有关它们行为方式的进一步线索,以便它可以更积极地优化代码。最后一个字段也是线程安全的,而您可能会在延迟初始化中弄乱非私有字段的状态。
我的建议是,你总是尽可能多地声明最终的,除非有明显的性能提升,否则不要做延迟/延迟初始化。
同样重要的是要记住,对数组或不可变对象的final
引用并不能保证如果您共享引用值(例如,直接通过 getter 返回它),其内容不会更改。裸数组没有解决方法,但对于java.util.*
集合,您始终可以共享对集合的不可修改包装引用(请参阅Collections.unmodifiableXXXX
方法)。
最后请注意,尽管将字段声明为带或不带final
的private
,但仍然可以使用一些时髦的低级检测来更改这些值(例如,请参阅此值)。但是,在编程时,没有人应该真正担心这一点。