首页 > 代码库 > 【喵"的Android之路】【番外篇】有关于null的一些知识点
【喵"的Android之路】【番外篇】有关于null的一些知识点
【喵"的Android之路】【番外篇】有关于null的一些知识点
1、首先,到底什么是null?
null是Java中的一个关键字,用于表示一个空对象引用,但其本身并不是任何类型也不是属于任何对象。因此,下面的做法是错误的:
int a = null;
但:
Object obj = null;
是可以的,因为null表示Object类型的一个空对象引用,符合其用意。
【注1】引用类型使用null声明对象变量后,无法使用该变量访问对象的成员。例如上述obj对象如果使用obj.toString()便会报NullPointerException。
【注2】需要注意的是,上边已经说过,null并不属于任何对象,它代表的是一个不确定的对象引用。所以此时使用instanceof进行实例判断的时候均会返回false,例:
1 String a = null;2 Object b = null;3 System.out.println(a instanceof String);// false4 System.out.println(b instanceof Object);// false
2、那么,为什么要使用null?
null的作用有两个,即在声明对象的时候延缓内存的申请开销和告知JVM可以回收的内存。
例1(不考虑常量池):
1 // 在栈内存中创建一个引用变量b;2 // 在堆内存中申请空间存储“Use Memory”字符串;3 // 把字符串的堆内存地址赋给变量b4 String b = new String("Use Memory");5 6 // 只在栈内存中创建一个引用变量a7 String a = null;
【注3】在不必立马指定对象实例的前提下,使用null可以尽可能节省空间。
例2:
1 // 声明对象并开辟空间保存User对象的值2 User user = new User(1, "张三", 23);3 4 // ... 经过一番处理后不再使用5 6 // 此时把user对象置为null,会告知JVM该对象不再被使用,可以进行回收7 // JVM在必要的时机会把user对象对应的空间回收8 user = null;
【注4】在确定对象不再使用的时候,使用null可以及时告知JVM等待回收的资源
3、一个关于null的调用困惑
看下边这段代码:
1 /* 2 ********************************************************** 3 *** *** 4 *** Copyright(C) 2014 Miao-Nodin. All rights reserved. *** 5 *** *** 6 *** Author: Miao-Nodin *** 7 *** *** 8 *** This is a source file of a part of a huge project. *** 9 *** Firstly, you must thank a pretty princess named ***10 *** Lady喵~喵~ for bestowing on you this honour that ge ***11 *** -ts this file. Who is she? She is my student. ***12 *** ***13 **********************************************************14 */15 package com.miao.base;16 17 /**18 * @Created: 2014年5月28日 by Miao-Nodin19 * @Description: 演示使用null访问对象方法20 *21 * @Version:1.022 * @Update:23 *24 */25 public class Null {26 private static final int LEVEL_ONE = 1;27 private static final int LEVEL_TWO = 2;28 private static final int LEVEL_THREE = 3;29 30 private static void say(int level) {31 switch (level) {32 case LEVEL_ONE:33 System.out.println("请你放尊重点,不要碰我!");34 break;35 case LEVEL_TWO:36 System.out.println("你再这样我要生气了!!!");37 break;38 case LEVEL_THREE:39 System.out.println("讨厌了啦~~~臭流氓~~~");40 break;41 }42 }43 44 public static void main(String[] args) {45 Null x = null;46 x.say(x.LEVEL_ONE); //正常输出47 ((Null) x).say(x.LEVEL_TWO); //正常输出48 ((Null) null).say(x.LEVEL_THREE); //正常输出49 }50 }
请你放尊重点,不要碰我!
你再这样我要生气了!!!
讨厌了啦~~~臭流氓~~~
你再这样我要生气了!!!
讨厌了啦~~~臭流氓~~~
困惑:【注1】中不是讲过,对象实例为null的变量不是无法访问对象的成员吗?为什么这里却可以正常调用方法?是不是Java的bug啊?
确实如此,【注1】讲的不错。但是,并不能说明上述代码是Java的bug。待我娓娓道来:
文章开头讲的很清楚,用null声明的对象是不包含对象实体的,此时如果用该对象变量访问对象实体必定会出错。但是,有一种情况例外!观察上述代码,被访问的成员变量和成员方法都有一个共性:被static修饰。对,就是这个static搞的鬼。我们知道,static类型的成员既可以被对象实例访问,也可以被类本身访问,也就是说它们是只与引用类有关而与对象实例无关的成员。
所以,当使用x.say(x.LEVEL_ONE)的时候,JVM检查x是Null的一个引用,便会不再进一步检查x是否被实例化过,而直接调用静态方法say(int)。第二种类似。第三种,直接使用null强制转换为Null对象,然后再调用say(int)方法,此时的((Null) null)相当于Null x = (Null) null; 如此便和第一种一致。
4、null的字符串相加困惑
看下面这段代码:
1 /* 2 ********************************************************** 3 *** *** 4 *** Copyright(C) 2014 Miao-Nodin. All rights reserved. *** 5 *** *** 6 *** Author: Miao-Nodin *** 7 *** *** 8 *** This is a source file of a part of a huge project. *** 9 *** Firstly, you must thank a pretty princess named ***10 *** Lady喵~喵~ for bestowing on you this honour that ge ***11 *** -ts this file. Who is she? She is my student. ***12 *** ***13 **********************************************************14 */15 package com.miao.base;16 17 /**18 * @Created: 2014年6月4日 by Miao-Nodin19 * @Description:演示null作为String类型空对象时的‘+‘操作20 *21 * @Version:1.022 * @Update:23 *24 */25 public class NullPlus {26 27 public static void plus() {28 String a = null;29 String b = null;30 String c = a + b;31 if("nullnull".equals(c)){32 System.out.println("This String-Object is not null.");33 }34 }35 36 /**37 * @param args38 */39 public static void main(String[] args) {40 plus();41 }42 }
输出结果:
This String-Object is not null.
困惑:null 加上 null为什么会是"nullnull"?
这个问题是String对‘+‘运算符的实现逻辑导致的。在Java中,String的‘+‘操作在被JVM编译后会使用StringBuilder的append(Object)方法代替,而StringBuilder的append(Object)方法源码如下:
1 /** 2 * @see java.lang.String#valueOf(java.lang.Object) 3 * @see #append(java.lang.String) 4 */ 5 public StringBuilder append(Object obj) { 6 return append(String. valueOf (obj)); 7 } 8 public StringBuilder append(String str) { 9 super.append (str);10 return this ;11 }
看得出,问题在String.valueOf(obj),null通过这个方法被转化为了"null",然后才有"nullnull"这种奇怪的问题。
附:plus()方法被JVM编译后的字节码
1 public static void plus(); 2 Code: 3 Stack=3, Locals=3, Args_size=0 4 0: aconst_null 5 1: astore_0 6 2: aconst_null 7 3: astore_1 8 4: new #15; //class java/lang/StringBuilder 9 7: dup10 8: aload_011 9: invokestatic #17; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;12 12: invokespecial #23; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V13 15: aload_114 16: invokevirtual #26; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;15 19: invokevirtual #30; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;16 22: astore_217 23: ldc #34; //String nullnull18 25: aload_219 26: invokevirtual #36; //Method java/lang/String.equals:(Ljava/lang/Object;)Z20 29: ifeq 4021 32: getstatic #40; //Field java/lang/System.out:Ljava/io/PrintStream;22 35: ldc #46; //String This String-Object is not null.23 37: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/String;)V24 40: return25 LineNumberTable:26 line 28: 027 line 29: 228 line 30: 429 line 31: 2330 line 32: 3231 line 34: 4032 33 LocalVariableTable:34 Start Length Slot Name Signature35 2 39 0 a Ljava/lang/String;36 4 37 1 b Ljava/lang/String;37 23 18 2 c Ljava/lang/String;38 39 StackMapTable: number_of_entries = 140 frame_type = 254 /* append */41 offset_delta = 4042 locals = [ class java/lang/String, class java/lang/String, class java/lang/String ]
另外,从上述字节码中也可以看出:源码中三行声明语句在Stack中一共创建了三个引用。至于创建了几个实例,请自行分析。
本文系Nodin原创,转载请注明出处!http://www.cnblogs.com/monodin/p/3841212.html
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。