当通过对象访问时,静态最终字段和在声明时初始化的实例最终字段之间的差异

时间:2015-07-19 14:21:31

标签: java static field constants final

  • 第一个例子

    public class MyClass {
        final int x = 2;
    }
    

    x

    1. final 表示初始化后永远无法设置。
    2. 在声明初始化,这意味着它以后不能为其分配不同的值(即使在构造函数中)。
    3. 已修复(无论实例如何),因为其值无法在构造函数中更改(或其他任何地方)。
  • 第二个例子

    public class MyOtherClass {
        static final int x = 3;
    }
    

    x

    1. final 表示初始化后永远无法设置。
    2. 在声明中初始化,这意味着以后不能为其分配不同的值。
    3. 静态字段,无论实例如何,该值始终保持不变。
    4. 常量,因为它既是静态又是最终

我的问题是

两者有什么不同? (不包括创作时间)

我错过了什么吗?

4 个答案:

答案 0 :(得分:6)

xMyClassMyOtherClass之间的差异是:

  • 第一个只能通过MyClass实例访问,并且可以有多个常量副本。

  • 可以在没有MyOtherClass实例的情况下访问第二个,并且只能存在一个副本。

在您的示例中,在具有一个或多个常量实例之间没有实际差异 1 。但请考虑一下:

public class YetAnotherClass {
    final int x;

    public YetAnotherClass(int x) {
        this.x = x;
    }
}

...显示实例常量如何在不同的实例中具有不同的值。

1 - 这是夸大其辞。首先,static final int x = 3;声明一个编译时常量,并且编译时常量可以用在switch case表达式中,其中非编译时常量可以是&t; t。其次,常量的非静态版本将在MyClass的每个实例中占用空间。最后,如果你足够愚蠢地尝试使用反射来改变常量,那么行为会有所不同。 (只是不要这样做......)

答案 1 :(得分:1)

虽然final,但JVM不进行任何优化或假设,因此该类的每​​个实例都将具有x的实例。如果您声明成员static,则该类的每个实例将共享同一个x实例,因为它是静态分配的。此外,正如书面(x具有包可见性),其他类可以静态访问x,即没有可用类的实例。

答案 2 :(得分:1)

如果您创建两种类型的多个实例,那么

在第一种情况下,MyClass的所有对象都有自己的final x字段。

在第二种情况下,MyOtherClass的所有对象都会指向一个final x类字段,因为它本质上是静态的。

答案 3 :(得分:1)

差异: 静态属于类所以你可以在没有任何类的实例的情况下访问它,因此只能访问它的一个副本。

虽然要访问第二个,但您需要一个类的实例来访问它,这样您就可以拥有与静态最终Object一样多的副本,因为它属于Object。

您可以使用字节代码进行验证: 对于静态

Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

非静态决赛

Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_2
         6: putfield      #2                  // Field x:I
         9: return
      LineNumberTable:

正如您所看到的那样, putfield 设置了objectref中标识的字段的值(对象的引用)