关于Java中的null值探究
来源:互联网 发布:usb网卡改mac 编辑:程序博客网 时间:2024/06/05 06:46
第一个问题-关于引用类型的null探讨
最近在补习数据结构-树的时候,发现了一个问题,发现一个null引用的有趣问题,先上代码:
1.Node.java
public class Node { public int data; public Node leftChild; public Node rightChild; public Node(int data) { this.data = data; leftChild = null; rightChild = null; }}
2.MyTree
public class MyTree { private Node root; public void insert(int value) { Node node = new Node(value); if (root == null) { root = node;//根节点 } else { Node current = root; while (true) { //左小右大 if (current.data > node.data) { //先找左边 current = current.leftChild; if (current == null) { current = node; System.out.println("左边插入之后current==node" + (current == node)); System.out.println("左边插入之后current==node" + (root.leftChild == node)); return; } } else { //再找右 current = current.rightChild; if (current == null) { current = node; System.out.println("右边边插入之后current==node" + (current == node)); System.out.println("右边插入之后current==node" + (root.leftChild == node)); return; } } } } } public Node getRoot() { return root; }}
3.测试代码:
MyTree mt = new MyTree(); mt.insert(3); mt.insert(2); mt.insert(1); mt.insert(4); Node root = mt.getRoot(); System.out.println(root.data);//3 System.out.println(root.leftChild);//null System.out.println(root.rightChild);//null
这样就尴尬了,为什么会这样的呢?明明就是current有引用的,但root的左右子树都是null,因此我做了下面这个实验:
Node node = new Node(1); Node left = node.leftChild; Node newNode = new Node(111); left = newNode; System.out.println(node.leftChild);//null
总结:
如下面的代码所示,其实上面的代码就是把一个null给了另外一个引用对象,null在java中代码没有引用任何对象(即没任何地址),所以就造成了上面的尴尬局面:
Apple a=null;APPle b=null;b=new APPle();//此时b有引用对象,a还是null
第二个问题-关于string类型null的探讨
String b=null+"111"; System.out.println(b);//null111 String bNull=null; String b1=bNull+"111111"; System.out.println(b1);//null111 String b2=b+b1; System.out.println(b2);//null111null111111
在很多时候,我们都学到一个空值+任何非null都会出现NullPointerException,当你运行上面的代码时候,会发现string类型的这种null居然不报,为什么呢?
个人理解:在c/c++中,+/-运算符都是可以被重载的,在Java核心1书本中提及了Java中的String类型的+是唯一被重载的,我认为是这里做了一定的处理(建议往下看)
进阶(先看下面代码):
1.Grandpa类
class Grandpa { public double salary; public int age; public String name; public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String getName() { return name; }}
2.Father类
class Father extends Grandpa { @Override public String toString() { return "Father{" + "salary=" + salary + ", age=" + age + ", name='" + name + '\'' + '}'; }}
3.测试代码:
Father father = new Father(); Grandpa grandpa = new Grandpa(); Father fatherNull=null; //com.test.Grandpa@74a14482ccccccccccc System.out.println(grandpa + "ccccccccccc"); //Father{salary=0.0, age=0, name='null'}ccccccccccc System.out.println(father + "ccccccccccc"); //nullccccccccccc System.out.println(fatherNull+ "ccccccccccc"); try { //java.lang.NullPointerException System.out.println(fatherNull.toString() + "ccccccccccc"); } catch (Exception e) { System.out.println(e); }
在这里亲友们可能发现了问题了吧???特别是最后两行的代码有木有感觉很意外呢?个人想解释的就是,String重载的+号作用是先把式子A+B+C中的A,B,C都变为字符串再进行相加的(非null的引用类型自动调用toString()方法,null引用类型的就直接给null表示),但最后一行很遗憾就是null.toString()方法是null指针调用方法了导致出现异常的
以上解释还是不合理的,继续探讨
StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(fatherNull); stringBuffer.append(father); //String.valueOf(father): Father{salary=0.0, age=0, name='null'} System.out.println("String.valueOf(father): "+String.valueOf(father)); //stringBuffer: nullFather{salary=0.0, age=0, name='null'} System.out.println("stringBuffer: "+stringBuffer.toString());
JDK中文文档叙述的:
Java 语言提供对字符串串联符号(”+”)以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。有关字符串串联和转换的更多信息,请参阅 Gosling、Joy 和 Steele 合著的 The Java Language Specification。
就是说String类型在运行+的时候其实就是调用 StringBuilder(或 StringBuffer)类及其 append 方法实现的,然后我们就需要看看源码的实现了;
1.首先来到了StringBuffer的Append方法
@Override public synchronized StringBuffer append(Object obj) { toStringCache = null;//这里不需要理会 super.append(String.valueOf(obj)); return this; } public AbstractStringBuilder append(String str) { if (str == null) return appendNull();//返回null int len = str.length(); ensureCapacityInternal(count + len);//扩容 str.getChars(0, len, value, count);//使用下面代码复制 // System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); count += len; return this; } //其实就是返回null private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4);//扩容,扩展成为c+4长度的数组 final char[] value = this.value; value[c++] = 'n'; value[c++] = 'u'; value[c++] = 'l'; value[c++] = 'l'; count = c; return this; }
2.String.valueOf(obj)源码
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
看完之后,你就会发现为什么Null会返回null了,看str参数的太多了,使用Object作为形参的来解释:是因为String.valueOf(obj)做了处理,obj为null就返回null要不然就调用obj.toString()
核心:是null的话就返回null,不为null就另外处理
PS:无论是在常量池字符串相加还是堆内存字符串相加,都是调用StringBuilder(或 StringBuffer)类及其 append 方法实现的
- 关于Java中的null值探究
- JAVA中的final探究
- 关于数据库中的NULL
- 关于java的null
- java中的多线程深入探究
- java中的null与空值
- java中的null与空值
- java 去除List中的null值
- Java 中的 null 对象
- JAVA 中的null
- Java中的null布局
- Java中的关键字null
- java中的null
- java中的null
- Java中的null
- Java中的NULL
- java中的null
- JAVA中的null
- AngularJS四大核心特性
- springmvc视图
- 1000·整数运算
- HIbernate多对多_查询
- Hibernate问题 failed to lazily initialize a collection of role
- 关于Java中的null值探究
- express实现登录注册(mysql+mongodb),简单添加session(两种)
- Git常用指令
- 入口文件
- Hibernate多对多_查询
- redux+react+webpack+热加载+兼容IE8(持续更新)
- angular的父子controller通信
- 【worldwind学习】worldwindjava高程数据客户端和服务器端配置
- JAVA 攻城狮 第二十三天