第一个输出1.0,因为三元运算符是一个整体,冒号后的double类使得整体精度提升;第二个输出1,正常情况。
new Integer(1) (然鹅,现在已经不支持new Integer()了…)创建对象,i == j中的 == 是判断是否是同一个对象,很明显不是,i == j 为false。
Integer m = 1;使用Integer中valueOf方法,其底层源码如下,可知:
所以 m == n 为true,x == y 为false
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
拓展:
示例5:i9返回值127,i10返回对象,故false;
示例6、7:只要有基本数据类型,比较的就是两个的值是否相同,故true。
a == b 为true,因为两个的地址是相同的,内存情况如下图:
a指向常量池中的“hsp”;b指向堆中对象(value),由value在指向堆中的对象,两者指向不一样,所以 a == b 是false
当调用intern方法时,如果池已经包含一个等于此 String 对象的字符串(用equals(Object)方法确定),则返回池中的字符串。否则,将此String对象添加到池中,并返回此 String对象的引用。即: intern()方法最终返回的是常量池的地址(对象)
已知a为常量池的地址,b为堆中的地址,故a == b.intern()为true,b == b.intern()为false。
p1.name == "hspedu"中,"hspedu"返回的地址就是常量池中的地址,所以true。
s1和s2分别指向堆中自己的value,所以只有最后一个为false。
创建了2个。先在常量池中创建“hello”,s指向它;之后由于之前常量池中没有“haha”,现在常量池中创建然后s指向“haha”
编译器不傻,会做优化,即判断创建的常量池对象 是否有引用指向。
String a = “hello” +“abc”; 会自动解释为 String a = “helloabc”;所以只创建了一个对象。字符串常量相加,直接看池地址。
c是如何创建的:
1.先创建一个StringBuilder sb = StringBuilder()
2.执行sb.append(“hello”);
3. sb.append(“abc”);
4. String c= sb.toString()
最后其实是 c指向堆中的对象(String) value[] ->池中“helloabc"
韩老师启示:一定要靠看源码来学习
判断内存图和输出:
只要调用方法(change)就会产生新栈。str = "java"的时候,str直接从指向堆中的value 改为 指向常量池中新创建的“java”;同时,堆中ch的第一个元素被改为h。change调用结束后,新栈立刻销毁,此时ex.str仍然指向堆中的value,value指向最初的hsp;ex.ch则是会输出hava。
string s=“a”;1/创建了一个字符串
s +=“b”;//实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+“b”(也就是"ab”)。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。结论: 如果我们对String做大量修改,不要使用String
看底层源码可知。结果如下:
4
null
// new StringBuffer时报错