我认为 A--C 的回答具有误导性:“我说得非常笼统,但如果它是最终的,那么无论如何你只需要它的一个实例,因此它通过使其成为静态来节省内存。” 正如其他人指出的那样,他将静态和最终混合在一起,这是两个非常不同的东西。恕我直言,这不是广义的,但不够精确,尤其是在解释基本概念时。
静态变量与类相关联,而不是与任何对象相关联。类的每个实例共享一个类变量,该变量位于内存中的一个固定位置。任何对象都可以更改类变量的值,但也可以在不创建类实例的情况下操作类变量。
另一边的最终变量是只能初始化一次的变量。它们的值不必在编译时知道,但可以在运行时设置。如果最终变量是实例变量,则该变量可以有许多实例,所有实例都具有不同的值。
静态最终变量是一个常量,因为只有一个,并且一旦初始化就不能在运行时更改。在 Java 中,至少在编译时不必知道该值。
现在这都是非常理论的,所以让我们举一个例子来展示这些类型的变量的用途:
public class Circle implements Serializable {
private static final long serialVersionUID = -1990742486979833728L;
private static int sNrOfCircles;
private final double mArea;
public Circle(double radius) {
sNrOfCircles++;
mArea = radius*radius*Math.PI;
}
}
serialVersionUID 将版本号与反序列化期间使用的 Circle 类相关联,以验证发送方和接收方是否已为该对象加载了与序列化兼容的类。serialVersionUID 永远不会改变,并且对于 Circle 的所有实例都是相同的。
sNrOfCircles 计算 Circle 实例的数量。它随着 Circle 的每个新实例而变化(而 serialVersionUID 从来没有)。
mArea 定义圆的面积。它也会随着 Circle 的每个实例而变化,但与 sNrOfCircles 相比,它与 Circle 对象相关联,而不是与 Circle 类相关联,而且它也不能被更改,而 sNrOfCircles 将在创建另一个 Circle 对象时发生变化。
简而言之:如果是 Class 属性(我们有多少个 Circles?),则使用 static,如果值在初始化后不会改变(具有给定半径的圆的区域),则使用 final,如果是,则使用 static final两个都。