Java String.valueOf()传入null值的问题

String.valueOf()传入null值的问题

今天在项目中遇到了一个String.valueOf()中传入null值的问题,刚开始颇为不解,后来经过百度和查看源码才得以解惑,记录下来,以防以后再次踩坑。上代码:

public class MyTest {
    @Test
    public void test(){
        String str = String.valueOf(null);
        System.out.println(str);
    }
    @Test
    public void test1(){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", null);
        String str = String.valueOf(map.get("id"));
        System.out.println(str);
    }
}

测试输出:
test()方法:

java.lang.NullPointerException
	at java.lang.String.<init>(String.java:166)
	at java.lang.String.valueOf(String.java:3008)
	at cloudboy.MyTest.test(MyTest.java:11)

test1()方法:

null

Process finished with exit code 0

因此很困惑啊,明明两个方法中传入的都是null值,为何一个报空指针异常,一个却是正常的。点击方法进入源码后才发现,它们进入了不同的方法:

 String str = String.valueOf(null);
 public static String valueOf(char data[]) {
        return new String(data);
    }
public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

另一个:

String str = String.valueOf(map.get("id"));
 public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

原来,valueof方法被重载多次,其中String.valueof(null)进入了valueof(char[] data)方法,valueof(char[] data)方法直接进入String构造器,内部会获取char[]的length,因此返回空指针异常。String.valueOf(map.get(“id”))却进入了valueOf(Object obj)方法,参数为null时,返回了一个字符串“null”,所以出现了不同的结果。

那重载方法是如何被选择的呢?
多个重载方法均能匹配的条件下,优先会选择精度高的那个,或者说范围小的那个,那上面的问题就明朗了,char[]和object均能匹配null值,而char[]是继承自object的(java中数组也是一种特殊的object),因此string。valueOf(null)优先选择精度高的char[],而String.valueOf(map.get(“id”))中map的v值已经声明为了object,所以它只能进入valueOf(Object obj)方法。

总结:java编译器在选择重载方法时,如果重载方法参数个数一致,且具备多个重载方法可以匹配到所传递的参数,此时,会优先选择精度相对较高的,即java继承树种树的深度较深的那个。

补充一下常见的一些考题:
例子1:

public class TestNull {
    public static void main(String[] args) {
        test(null);   //此处将返回arraylist,因为list同arraylist存在继承或实现的上下级关系
    }

    static void test(List list) {
        System.out.println("list");
    }

    static void test(ArrayList list) {
        System.out.println("arraylist");
    }
}

结果:输出arraylist

例子2:

public class TestNull {
    public static void main(String[] args) {
        test(null);   //本行会编译报错
    }

    static void test(String str) {
        System.out.println("string");
    }

    static void test(Integer num) {   //如果修改为int,则编译通过
        System.out.println("integer");
    }
}

结果:编译失败
因为构造函数是编译时期确定的,代码将无法通过编译,因为String同Integer不存在任何关系,他们都继承自Object,他们的公共父类是object(String和String[]也是一样的道理),此时null值不知道该传入那个方法,因此无法通过编译,将报错。

你可能感兴趣的:(Java基础)