【问题标题】:Are non-static final variables useful in Java?非静态最终变量在 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

标签: java


【解决方案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; 是没有意义的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 2011-11-25
      • 1970-01-01
      • 1970-01-01
      • 2011-01-25
      • 1970-01-01
      相关资源
      最近更新 更多