Java中final关键字的用法

3
我想知道以下两者之间的区别:

public final type attribute_name;

and

private type attribute_name;
public type getA_name() {
  return attribute_name;
}

我想让一个属性变成只读的,这样在初始化后就不能更改了。
我应该将其设置为public final,还是将其设置为private,并只通过get方法(没有set方法)来访问它?

7个回答

4

当类的成员变量不是final而是private时,该类本身可以更改该值。


1

final字段在构造函数退出之前必须被设置。一旦设置,引用就不能被修改(值不能被重新分配)。强调不能被重新分配。这意味着虽然引用不能改变,值本身可以改变

以下是合法的:

final List<Integer> list = new List<Integer>();
list.add(5); // the value of list changes, but the reference doesn't

这不是:

final List<Integer> list = new List<Integer>();
list = new List<Integer>(); // may seem sort of redundant but the compiler won't allow it nonetheless

一个带有只读取器的private变量可以被包含它的类内部重新分配(但在外部不可见,因此不能在持有它的类之外重新分配)。此外,在类之外,引用是不可访问的,因此除了持有它的类之外,变量不能被修改。

final变量无法在任何地方重新分配,但如果它是公共的,则另一个类仍然可以访问引用并更改其指向的任何对象的值。

如果您不希望变量在初始化后被重新分配,如您所描述的那样,请同时使用finalprivate


使用 final 来表示类似这样的东西:
public class User {

    private final long registrationTimeMillis;

    public User(/* various parameters probably would be here */) {
        registrationTimeMillis = System.currentTimeMillis();
    }

    public long getRegistrationTimeMillis() {
        return registrationTimeMillis;
    }
}

我们不希望用户的注册时间发生变化,因此在创建后不允许更改是合理的。

对于这样的情况,请使用没有setter的private

public class VendingController() {

    private int drinksStocked = 0;
    private int drinksDispensed = 0;

    public void dispenseDrink() {
        drinksDispensed++;
    }

    public void stockDrinks(int numberOfDrinks) {
        drinksStocked = getDrinksRemaining() + numberOfDrinks;
        drinksDispensed = 0;
    }

    public int getDrinksRemaining() {
        return drinksStocked - drinksDispensed;
    }
}

我们不希望drinksDispensed的值在没有调用dispenseDrink()或者stockDrinks(int numberOfDrinks)时发生改变。然而,在售货机重新填充时,它仍然需要被自己的类重新分配,因此我们不应该将其声明为final。请注意,需要保留html标签。

关于使用 public final,通常在Java中只针对常量进行这样的操作,并且还包括 static 关键字,因为常量不应该依赖于一个实例。

以下是使用 public static final 的合理情况示例:

public class UnitConversions {

    public static final double CENTIMETERS_PER_INCH = 2.54;

}

它可以在方法中按如下方式使用。
public double convertFromCentimetersToInches(double centimeters) {
    return centimeters / UnitConversions.CENTIMETERS_PER_INCH;
}

祝你好运,OP,编程愉快。

更多关于final fields的阅读材料


问题是关于字段,而不是方法。 - SirRichie
问题在于将其设置为public final或者是使用get方法私有化,二者之间的区别是什么。 - Don
“String” 可能会给人们带来误导,因为它是不可变的。 - Bathsheba
好吧,重点是引用无法重新分配,但也可以。我更改了该示例以使用“long”。 - Michael Goldstein
“在构造函数退出之前,必须设置最终字段” - 这并不适用于Java。 - Jonathan
显示剩余4条评论

1
最终修饰符允许字段只被赋值一次 - 在此之后它不能被更改,并且必须在对象构建期间设置(也就是在构造函数返回之前设置)。
如果您想使字段只读,请使用信息隐藏的原则:将其设置为私有,并提供一个公共getter来返回该字段(对于非基本类型,返回其副本)。
只有对于真正的常量才应使用public final。 即使由于final而使字段不可变,仍然将其设置为private通常是一个好主意。

1
这取决于一些因素。
如果这是一个已知且永远不会改变的真实常量,则使用 final。在 Java 中,final 字段也可以在构造函数中初始化,因此如果您的值在构建时已知,则也可以使用 final。
如果该值在运行时设置(一次或多次),则使用 private + getter。

1
刚好比我先到那里了 ;) 重要的是,OP不必在“private”和getter之间进行选择,而是两者都可以使用。 - Mardoz

0
正确的方式是着眼未来,思考什么可以帮助您实现目标。也许以后您想为那个变量赋值。如果我是您,我会创建一个get方法并将变量保持为私有的来完成这个操作。 final关键字的完整文档:http://en.wikipedia.org/wiki/Final_(Java)

0

这取决于您想从哪里访问它。公共变量可以从项目和包中的任何类中访问,而私有变量只能从变量所在的类中访问。

'final'运算符使其成为永久和只读的。


0

假设type是一个对象的引用,而不是原始类型。

  1. public final type attribute_name表示attribute_name不能被重新分配到其他地方。但是,attribute_name可以用于调用改变其状态的方法。

  2. private type attribute_name中,只有类内部的方法才能调用attribute_name上的方法。

因此,如果您希望保持其恒定性,请使用方法(2)。将public方法限制为最终调用不修改其状态的attribute_name方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接