非静态最终变量在 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 不会使最后一个示例变得更好。有Collections 可以截断所有变异方法,但这会给我们带来唯一的好处是运行时错误。编译器在这里帮不上忙。

【讨论】:

谢谢 :) 我从来没有接触过 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 中有用吗?的主要内容,如果未能解决你的问题,请参考以下文章

一个类中直接调用另一个类的静态方法吗

java中静态变量和静态方法的优缺点

内部类访问外部类的变量必须是final吗,java静态方法中不能引用非静态变量,静态方法中不能创建内部类的实例

java中为啥说静态方法先执行?

java覆盖和隐藏

Xposed怎样hook 静态变量的调用