非静态最终变量在 Java 中有用吗?
Posted
技术标签:
【中文标题】非静态最终变量在 Java 中有用吗?【英文标题】:Are non-static final variables useful in Java? 【发布时间】:2014-11-01 03:23:44 【问题描述】:这个问题讨论了非静态最终变量的做法。
我的第一印象是非静态的final变量是没用的,因为final变量在初始化后不能重新赋值。
class Foo
public static final int BAR = 10;
这意味着从Foo
类型创建的所有对象都将具有BAR = 10
。
像这样使用非静态但最终的变量什么时候有用、实用或被接受?
class Foo
public final int BAR = 10;
那么在什么情况下后者变得有用呢?因为它基本上意味着同样的事情。
【问题讨论】:
如果你在ctor中设置了。 “在变量上使用 final 修饰符,初始化后没有什么可以改变它,对吧?” – 在你的例子中,是的。但是,请注意不要将 Java 中的final
与 C++ 中的 const
混淆。如果它不是原始类型,而是带有可以通过公共方法更改的状态的类,那么即使变量声明为final
,该状态也可以更改。
@JClassic did so
【参考方案1】:
当同一只动物有这样的领域时:
private final Animal mother;
每个人只有一个亲生母亲,没有共同的母亲,这意味着每个实例都是特定的。
设为static
表示该值在所有实例之间共享。如果这是你想要的,那当然是有道理的。
【讨论】:
如果你内联初始化了变量,所以它们都有相同的“母亲” 这没有多大意义,但可以肯定的是:如果您假设每个实例的值都相同,那么您不妨将其设为static
。
谢谢,这是我的问题。【参考方案2】:
Java 中的final
不应与 C++ 中的const
混淆。声明一个变量final
意味着它不能被重新赋值。如果变量是原始类型,这很好。如果变量是引用类型,声明它final
不会阻止它发生变异。
这是安全的(因为int
是原始类型)并且被普遍接受:
class Week
public static final int NUMBER_OF_DAYS = 7;
Week.NUMBER_OF_DAYS = 6; // error: cannot reassign final variable
这也是安全的。虽然java.lang.String
不是原始类型,但它保证是不可变的。 (即String
没有任何方法可以改变它的值,它绝对不能得到一个,否则一个相当基本的语言级别的契约会被破坏。)我仍然发现很多人不喜欢这种公共属性的使用,并且许多风格指南禁止它。
class Weekday
public final String name;
public Weekday(String name)
this.name = name;
Weekday monday = new Weekday("Monday");
monday.name = "Tuesday"; // error: cannot reassign final variable
这不安全:
class Week
public static final String[] DAYS_OF_THE_WEEK =
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
;
Week.DAYS_OF_THE_WEEK = new String[6]; // error: cannot reassign final variable
Week.DAYS_OF_THE_WEEK[2] = "February"; // this is not prevented!
使用java.util.Collection
不会使最后一个示例变得更好。有Collection
s 可以截断所有变异方法,但这会给我们带来唯一的好处是运行时错误。编译器在这里帮不上忙。
【讨论】:
谢谢 :) 我从来没有接触过 c++,但我想这个场景并没有出现在我的脑海中【参考方案3】:一个常见的用例是锁定对象。
private final Object lock = new Object();
...
synchronized(lock) ...
这种模式有时要求锁对象属于实例而不属于类 (static
)。
【讨论】:
【参考方案4】:如果字段类型是不可变的,那么只有当它是由构造函数分配的值时才有意义。
final class Point
final double x, y;
Point(double x, double y)
this.x = x;
this.y = y;
如果该字段的值是可变的,那么在其声明站点初始化一个 final
字段确实有意义,因为每个实例都会获得自己的引用。
final class ListWrapper<A>
final List<A> list = new ArrayList<>();
但是在您给出的示例中,不,将字段初始化为 public final int SIZE = 10;
是没有意义的。
【讨论】:
以上是关于非静态最终变量在 Java 中有用吗?的主要内容,如果未能解决你的问题,请参考以下文章