java中的null到底是什么?

这篇博客深入探讨了Java中的null值,通过字节码解析和C++的视角理解null的含义。作者发现null在内存中表示为0,但出乎意料的是,null调用方法居然没有引发空指针异常。原来是编译器在幕后做了优化,将null转换为了对象实例。博客揭示了Java编译器的智能行为以及null在不同语言中的差异。
摘要由CSDN通过智能技术生成

前言

无论从事什么职业,曾经在哪里工作,总要留下自己的一些痕迹。
也许是多年以后的某一天,你蓦然回首,你可以淡淡的说一句,来过!


一、null是什么?

我相信你肯定觉得这个问题很白痴,别着急,看代码:

/**
 * @author top
 */
public class NullClassTest {

    public static void sayHello() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        ((NullClassTest) null).sayHello();
        
        NullClassTest nullClassTest = null;
        nullClassTest.sayHello();
    }
}

请问以上代码编译能通过吗?如果通过了运行会报空指针异常吗?

别急我们接着往下看,打开NullClasTest的字节码:

 public static void main(java.lang.String[]);
   descriptor: ([Ljava/lang/String;)V
   flags: ACC_PUBLIC, ACC_STATIC
   Code:
     stack=1, locals=2, args_size=1
        0: aconst_null
        1: checkcast     #5                  // class com/myhexin/test/NullClasTest
        4: pop
        5: invokestatic  #6                  // Method sayHello:()V
        8: aconst_null
        9: astore_1
       10: aload_1
       11: pop
       12: invokestatic  #6                  // Method sayHello:()V
       15: return
     LineNumberTable:
       line 13: 0
       line 15: 8
       line 16: 10
       line 17: 15

我们看到第一个指令:aconst_null
通过查看虚拟机字节码指令表知道这条指令的含义是将null推送到栈顶,但是更多的信息就没有了,线索似乎到这里中断了。
别急,我们再看,我们知道Java是一门解释性语言(别杠,杠就是你对),虚拟机字节码指令需要解释器解释为机器指令才能执行。hotspot虚拟机中的zero解释器有这样一段代码:

	#define NULL 0
	...
	#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value))
	...
      CASE(_aconst_null):
          SET_STACK_OBJECT(NULL, 0);
          UPDATE_PC_AND_TOS_AND_CONTINUE(1, 1);
      
      

SET_STACK_OBJECT(NULL, 0)代码的含义是将栈中偏移量为0的位置的值设为0.
所有在内存中null的值其实是零。这似乎跟我们猜想的不太一样他怎么会是0呢?
0的含义是什么?我们知道java的宿主语言是C++,那么C++中会不会有我们想要得答案呢?
恰巧博主在学习C++的过程中看到过一段话:
在这里插入图片描述
原来0代表不指向任何一个可访问的地址。
那么我们开局的代码运行结果是什么呢?根据上边我们一步一步的推导你肯定在想爱,是报空指针啦!
错,错,错!
通过程序运行:
在这里插入图片描述
不仅没报错反而正确运行了。null不是指向不指向任何可访问的地址吗?这怎么还调用成功了呢?
其实呢这一切的一切都是编译器在作怪,我们用ide工具打开编译后的class文件,当然牛逼的可以直接看字节码指令,但是通过ide查看会更直观:

public class NullClassTest {
    public NullClassTest() {
    }

    public static void sayHello() {
        System.out.println("hello");
    }

    public static void main(String[] args) {
        NullClassTest var10000 = (NullClassTest)null;
        sayHello();
        NullClassTest nullClassTest = null;
        sayHello();
    }

开具的代码经过编译器的处理变成了以上的形式,其实是编译器偷偷改了我们的代码,他替我们写了正确的调用方法。
以上就是就是Java中的null,觉得有帮助的可以点个赞。
ps:zero解释器的代码路径:hotspot源码下的src\share\vm\interpreter\bytecodeInterpreter.cpp

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值