关于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 方法实现的

原创粉丝点击