最近复习SCJP头都大了。大家看看下面这种用法:public class NullToClassRefrence{
public static int i;
public static void main(String[] args){
NullToClassRefrence o = null;
o.i=3;//这样也行,大家分析下这是什么机制?
System.out.println(i); }
}解释是这样说的:
Please note that a null reference may be used to access a class (static) variable without causing an exception. The static variable is called on the class itself and not on the object.
还是不太明白,我也知道静态变量是类去调用的,而不是某个特定的对象去调用,但是这种用法。。想不通啊
难道只要i是静态变量,就把 o.i =3 (o必须是该类的引用)在编译期间当作 NullToClassRefrence.i来看待?

解决方案 »

  1.   

    静态变量,不需要申请空间,所以reference为null时也能用该类的static变量了
      

  2.   

    但NullToClassRefrence o = null;
    这样一写,JVM就会在某个时候把 o 给垃圾回收掉,再引用的时候就会报错啊
      

  3.   

    但NullToClassRefrence o = null;
    这样一写,JVM就会在某个时候把 o 给垃圾回收掉,再引用的时候就会报错啊
    ---------------------------------------------------
    再引用会报错那是调用实例方法或访问实例属性才会报错,因为虚拟机找不到入口地址(内存空间被回收,不存在了)。这里的所谓会报错仅针对于调用实例方法或访问实例属性,也就是堆内存区
    如果是调用类方法或访问类属性(也就是静态方法或静态属性),虚拟机会到静态内存区去寻找入口地址,而一旦类被加载,静态内存区就会存在,虚拟机也就可以找到相应的入口地址,当然就不会报错了
      

  4.   

    但NullToClassRefrence o = null;
    这样一写,JVM就会在某个时候把 o 给垃圾回收掉,再引用的时候就会报错啊
    ======================
    o回收掉怕啥?静态方法根本不需要o,你甚至可以仅仅把它当作一个编译时的符号而已(对静态方法而言)。只要那个类不要被JVM卸载就行了。但问题是既然类的静态方法会被调用,JVM加载这个类还来不及呢,又怎么可能故意卸载它呢?你只需要注意:
    NullToClassRefrence o = null;
    o.i ……
    并不等价于:
    null.i ……
    就可以了。
    o是有类型信息的,而“类型明确”则足以构成调用静态方法的充分条件,因为static方法的调用仅仅以来于类,不依赖于任何对象。至于是否有实例、是否是null,是否将被回收,都无关紧要。最后,其实“会在某个时候把 o 给垃圾回收掉”这种说法本身就是错误的,垃圾回收器回收的是对象,而不是引用名称,o仅仅是个名称,它可能在某个时候引用着某个对象,而在另一个时候引用着另外一个对象(比如连续new了两次对象赋给o)。而当它不再引用某个对象的时候,那个对象才可能被回收,而不是“o”被回收。而如果一个引用为“null”,也就是说它还没有引用任何对象,那么也就根本不存在“谁谁会被回收”这种说法。没有对象,哪来的回收?
      

  5.   

    难道只要i是静态变量,就把 o.i =3 (o必须是该类的引用)在编译期间当作 NullToClassRefrence.i来看待?搂主的观点就是正解。
    java的binary code里面读写Field和调用Method的指令是严格区分静态和非静态的,相关指令如下:
    读写字段的指令:getfield getstatic putfield putstatic 
    调用静态方法:ivokestatic 
    调用非静态方法以及构造函数:ivokevirtual/ivokespecial/ivokeinterface因此,在编译的过程中就要识别字段或函数是否为静态。在搂主的例子中,o.i=3会被翻译成NullToClassReference.i=3另外,对于此类问题,可以用JDK/bin目录下的javap.exe来分析/比较
      

  6.   

    哦,对垃圾回收又有了新的认识,谢谢个位。
    我再多问一句:
    ------------------steedhorse(晨星)
    “o回收掉怕啥?静态方法根本不需要o,你甚至可以仅仅把它当作一个编译时的符号而已(对静态方法而言)。只要那个类不要被JVM卸载就行了”
    -----------------一个对象可以在没有引用指向他的时候被回收掉,
    那什么时候一个类会被JVM卸载呢?------------------qybao(阿宝) 
    “一旦类被加载,静态内存区就会存在”
    ----------------静态内存区是指的栈中,那一个程序运行起来之后,栈内存区中的内容什么时候会被清除了?
      

  7.   

    静态内存区是指的栈中,那一个程序运行起来之后,栈内存区中的内容什么时候会被清除了?
    ------------------------------------------------------
    静态内存区怎么会在栈中内,你好好看下书吧
    对于编译器来说,内存总是分为静态区(也就是全局区),堆区和栈区三部分虚拟机一般在程序启动的时候就会根据字节代码把相应的类加载进来,除非有些是动态加载的,比如数据库驱动什么的,至于什么时候卸载,应该是不确定的吧,因为虚拟机也不知道用户会在什么时候用到加载的类,如果卸载了,后面还用到该类,虚拟机就要重新加载,估计就会影响效率了
    详细可以参看一下java虚拟机的原理,我还没怎么有空研究过