Java中空引用上的静态字段

Java中空引用上的静态字段,java,static,Java,Static,Java中的static成员(static字段或static方法)与各自的类相关联,而不是与此类的对象相关联。以下代码试图访问null引用上的静态字段 public class Main { private static final int value = 10; public Main getNull() { return null; } public static void main(String[] args) {

Java中的
static
成员(
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
。这段代码是如何工作的?

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

从实例引用访问静态字段的能力(正如您所做的那样)只是一种语法上的糖分,没有其他意义。
您的代码编译为

main.getNull(); 
Main.value

该行为在以下文件中规定:

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

在更详细的信息中,例如
Primary.staticField
的工作原理如下(强调我的)——在您的例子中,
Primary=main.getNull()

  • 对主表达式求值,并丢弃结果。[……]
  • 如果字段是非空的final字段,则结果是主表达式类型的类或接口中指定的类变量的值。[…]
  • 访问具有类名的
    静态
    成员是合法的,但不是 已写入无法使用 对象引用变量。所以它在这里工作

  • 允许
    null
    对象引用变量访问
    静态
    类 在编译或运行时不引发异常的变量 时间


  • 当您在编译时访问带有对象的静态变量或方法时,它会转换为类名。例如:

    Main main = null;
    System.out.println(main.value);
    
    它将打印静态变量value的值,因为在编译时它将转换为

    System.out.println(Main.value);
    
    证明:


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

    静态变量和方法始终属于类。所以,当我们创建任何对象时,只有非静态变量和方法和对象一起进入堆,而静态变量和类一起驻留在方法区域。这就是为什么当我们试图访问静态变量或方法时,它会转换为类名点变量或方法名

    请参阅下面的链接了解更多详细信息


    也许这个问题可以帮助你理解它:为了好玩,试试
    Main=null;main.getNull().value
    。这让我想起了
    新线程[]{}[-1]。睡眠(10)其中sleep()是一个静态方法。这在一些较旧的Java版本上曾经成功过。如果有人知道为什么会做出这样的选择,这会很有趣。@JonofAllTrades我认为这是显而易见的:调用空引用时不抛出任何异常是合理的,因为它不重要,因为方法是静态的。@JonofAllTrades:真正的问题是为什么选择允许静态成员作为实例调用。。。对我来说,这似乎只会导致混乱和可读性较差的代码。@Falanwe:同意,这是一个我不需要的构造,尽管我大部分工作在.NET中,那里是不允许的。我猜当您被赋予对父类的引用时,您可能想调用子类的相应静态方法。@Falanwe这是允许的,但在Eclipse中会引发一个警告:“静态字段Main.value应以静态方式访问”。至少我们这些对警告挑剔的人(像我一样)会避免这样的代码。我称之为语法糖,更像是语法锯末;)