Java中的空引用上的静态字段


119

staticJava中的成员(static字段或static方法)与各自的类关联,而不是与此类的对象关联。以下代码尝试访问null引用上的静态字段。

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

虽然main.getNull()返回了null,但它可以工作并显示value = 10。该代码如何工作?



4
为了娱乐,请尝试Main main = null; main.getNull().value
Marko Topolnik

1
这让我想起了new Thread[]{}[-1].sleep(10);sleep()是静态方法的地方。这曾经在某些较旧的Java版本上成功。
2012年

Answers:


93

该行为在Java语言规范中指定:

空引用可用于访问类(静态)变量,而不会引起异常。

更详细地讲,进行静态场评估,例如Primary.staticField以下工作(重点是我的工作)-在您的情况下Primary = main.getNull()

  • 计算主表达式,并丢弃结果。[...]
  • 如果该字段是非空白的final字段,则结果是在类或接口中指定的类变量的值,该值是Primary表达式的类型。[...]

5
如果有人知道为什么做出此选择,那将很有趣。

6
@JonofAllTrades我认为这很明显:在调用null引用时不抛出任何异常是合理的,因为由于该方法是静态的,所以没有关系。
马尔科姆

13
@JonofAllTrades:真正的问题是为什么要做出允许将静态成员作为实例进行调用的选择……对我而言,这似乎只会导致混乱和可读性差的代码。
Falanwe,2012年

2
@Falanwe:同意,这是我不需要的构造,尽管我主要在不允许的.NET中工作。我猜想当您获得对父类的引用时,您可能想调用子类的适当静态方法。

8
@Falanwe这是允许的,但是在Eclipse中引发警告:“应该以静态方式访问静态字段Main.value”。至少我们这些对警告挑剔的人(像我一样)会避免使用此类代码。
Artyom,2012年

19

正如您所说,因为静态字段不与实例关联。

从实例引用访问静态字段的能力(如您所做的)仅是语法糖,没有其他含义。
您的代码编译为

main.getNull(); 
Main.value

7
我将其称为句法糖,更像是句法锯末;)
Stephen Swensen 2012年

3

每当您在编译时使用对象访问静态变量或方法时,它都会转换为Class名称。例如:

Main main = null;
System.out.println(main.value);

它将打印静态变量value的值,因为在编译时它将被转换为

System.out.println(Main.value);

证明:

下载反编译器并将您的.class文件反编译为.java文件,您会看到所有静态方法或变量引用的对象名将自​​动替换为类名。


3
  1. static使用类名访问成员是合法的,但是没有写到不能static使用对象引用变量访问成员。所以它在这里工作。

  2. null对象引用变量被允许访问一个static类变量,而不在编译或运行时抛出异常任一。


2

静态变量和方法始终属于类。因此,无论何时创建任何对象,只有非静态变量,方法都会与对象一起堆放,而静态则与类一起位于方法区域。这就是为什么我们每次尝试访问静态变量或方法时都会将其转换为类名,点变量或方法名的原因。

请参考以下链接了解更多详情。

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.