null的伟大与可怕 之 String字符串
null的伟大与可怕 之 String字符串 1
http://blog.youkuaiyun.com/sunrainamazing/article/details/71591334
null的伟大与可怕 之 String字符串方法2
http://blog.youkuaiyun.com/sunrainamazing/article/details/71593030
null的伟大与可怕 之 Optional操作 3
http://blog.youkuaiyun.com/sunrainamazing/article/details/71596437
基本类型会被自动初始化为
byte short int long –> 0
float double –>0.0
boolean –> false
char –> ” 转换成int 为 0 空字符
引用类型则统一为 null ,但是对象引用会被初始化为 null。
当尝试调用null对象的方法,就会抛出空指针异常。
但是 通常,print 一个 null 对象而不会抛出异常,且输出的值为 null。
那么为什么可以输出一个 null 对象不会抛出异常且值为null?
是不是null对象的值就是null呢?
package sun.rain.amazing.strnull;
/**
* Created by sunRainAmazing on SUN_RAIN_AMAZING
* @author sunRainAmazing
*/
import sun.rain.amazing.bean.User;
import org.junit.Test;
public class StringNull {
/**
* 测试String 类型的 null对象
*/
@Test
public void testStringNull(){
String str = null;
System.out.println(str);
}
/*
没有抛出异常,而是打印了null。
显然问题的线索在于print函数的源码中。我们找到print的源码:
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
看到源码才发现原来就只是加了一句判断而已,简单而又粗暴,仅赋值为 null。
*/
/**
* 测试非String 类型的 null对象
*/
@Test
public void testNoStringNull1(){
Object obj = null;
System.out.println(obj);
}
/**
我们再去看看print的源码:
public void print(Object obj) {
write(String.valueOf(obj));
}
有点不一样的了,看来秘密藏在valueOf里面。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
看到这里,我们终于发现了打印 null 对象不会抛出异常的秘密。
print方法对 String 对象和非 String 对象分开进行处理。
【String 对象】:直接判断是否为null,如果为 null给null对象赋值为"null"。
【非 String 对象】:通过调用String.valueOf方法,
如果是 null 对象,就返回"null",否则调用对象的toString方法。
通过上面的处理,可以保证打印 null 对象不会出错。
*/
/*
===================================
null 对象与字符串拼接会得到什么结果?
String s = null;
s = s + " is not null ";
System.out.print(s);
===================================
编译器对字符串相加会进行优化,首先实例化一个StringBuilder,
然后把相加的字符串按顺序append,
最后调用toString返回一个String对象。
String s = "a" + "b";
//等价于
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
String s = sb.toString();
再回到我们的问题,现在知道秘密在StringBuilder.append函数的源码中。
//针对 String 对象
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//针对非 String 对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
//针对 null对象
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
现在我们恍然大悟,append函数如果判断对象为 null,
就会调用appendNull,填充"null"。
*/
@Test
public void testAppend(){
StringBuffer sBuffer = new StringBuffer("ad");
sBuffer.append("D_");
sBuffer.append(new User());
System.out.println(sBuffer.toString());
//sun.rain.amazing.bean.User@7aec35a
}
}