一、integer的==
public class Test03 {
public static void main(String[] args) {
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System. out.println( f1 == f2); //true
System. out.println( f3 == f4); //false
}
}
当我们给一个 Integer 赋予一个 int 类型的时候会调用 Integer 的静态方法 valueOf。
Integer f1 = Integer.valueOf(100);
Integer f2 = Integer.valueOf(100);
Integer f3 = Integer.valueOf(150);
Integer f4 = Integer.valueOf(150);
思考:那么 Integer.valueOf()返回的 Integer 是不是是重新 new Integer (num); 来创建的呢?如果是这样的话,那么 == 比较返回都是 false,因为他们引用的堆地址不一样。
具体来看看 Integer.valueOf 的源码
public static Integer valueOf(int i) {
//范围-128到127
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从上面我们可以知道给 Interger 赋予的 int 数值在 - 128 - 127 的时候,直接从 cache 中获取,这些 cache 引用对 Integer 对象地址是不变的,但是不在这个范围内的数字,则 new Integer (i) 这个地址是新的地址,不可能一样的.
注意
Integer的默认值是null(对象的默认值都是null)
int类型默认值是0.
二、string的==
-
String str=new String (“abc”) 和 String str=“abc” 的字符串 “abc” 都是存放在堆中,而不是存在栈中。
-
其实在在 java 中有一个 “字符数据池” 的内存管理机制。
-
String str=“abc”,执行这句话时,会先去 “字符数据池” 搜索时候有 “abc” 这个字符串,如果有,则将字符串的首地址赋值给 str,如果没有,生成一个新的字符串 “abc” 并且将首地址赋值给 str;
-
String str=new String (“abc”),执行这句话时,会现在堆里面生成一个对象,str存储的是这个对象的地址,同时,会去查看字符常量池中是否存在该字符串,如果存在就不处理,如果不存在,还会在字符常量池中生成一个相同的字符串。
-
由以上分析可知,String str=“abc” 和效率要高于 String str=new String (“abc”),因为如果有重复的字符串时,第一种方式可以节省空间。
-
下面举例说明一下,好好看看结果,仔细分析原因,上面已经说明的很清楚了:
public class Test{
public static void main(String args[]){
String s1=new String ("abc");// 直接在堆中生成新的 “abc”
String s2=new String ("abc");// 直接在堆中生成新的 “abc”
String s3="abc";// 先去 “字符数据池” 搜索时候有 “abc” 这个字符串,如果有,则将字符串的首地址赋值给 s3,如果没有,则在 “字符数据池” 中生成一个新的字符串 “abc” 并且将首地址赋值给 s3;
String s4="abc";// 去 “字符数据池” 搜索时发现了上一步生成的 “abc” 这个字符串,把该字符串首地址赋值给 s4,这时其实 s3 和 s4 指向同一个字符数据池中的 “abc”
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s2==s3);
System.out.println(s3==s4);
}
}
结果:
false
fasle
false
true
总结
综上所述,创建字符串有两种方式:两种内存区域(pool,heap)
String 对象的不可变性
toUpperCase () 会对当前对象进行检查 如果不需要转换直接返回当前对象,否则 new 一个新对象返回;
replace () 如果两个参数相同,则直接返回,否则 new 一个新对象
1," " 引号创建的字符串在字符串池中
2,new,new 创建字符串时首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址
补充:
- String s1 = new String (“abc”); 这句话创建了几个字符串对象?
将创建 1 或 2 个字符串。如果池中已存在字符串文字 “abc”,则堆中只会创建一个字符串 “s1”。如果池中没有字符串文字 “abc”,那么它将首先在池中创建,然后在堆空间中创建,因此将创建总共 2 个字符串对象。 - String s = “aaa” + new String(“bbb”);
上面创造了几个对象呢
答案是 4 个,ps: 前提是 pool 都没有这四个字符串
“aaa” 一个对象(池)
new Sring () 一个对象(堆)
“bbb” 一个对象(池)
“aaa” + new new Sring () 一个对象(池)
例如:
String str1=”java”; // 指向字符串池
String str2=”blog”; // 指向字符串池
String s=str1+str2; //s 是指向堆中值为 “javablog” 的对象,+ 运算符会在堆中建立来两个 String 对象,这两个对象的值分别是 “java” “blog”. 也就是说从字符串池中复制这两个值,然后在堆中创建两个对象,然后再建立对象 s, 然后将 “javablog” 的堆地址赋给 s.
System.out.println (s==”javablog”); // 结果是 false。
Jvm 确实对型如 String str1=”java”; 的 String 对象放在常量池里,但是它是在编译时那么做的,而 String s=str1+str2; 是在运行时刻才能知道,也就是说 str1+str2 是在堆里创建的,所以结果为 false 了。
如果改成一下两种方式:
String s=“java” + “blog”; // 直接将 “javablog” 放入字符串池中,System.out.println (s==”javablog”); 的结果为 true,
String s=str1+ “blog”; // 不放入字符串池,而是在堆中分配,System.out.println (s==”javablog”); 的结果为 False
三、基本类型和包装类的==和equals(涉及拆装箱)
1、基本型和基本型封装型进行 “= =” 运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此 Integer (0) 会自动拆箱为 int 类型再进行比较,显然返回 true;
2、两个 Integer 类型进行 “= =” 比较,如果其值在 - 128 至 127,那么返回 true,否则返回 false, 这跟 Integer.valueOf () 的缓冲对象有关,这里不进行赘述。
3、两个基本型的封装型进行 equals () 比较,首先 equals () 会比较类型,如果类型相同,则继续比较值,如果值也相同,返回 true
4、基本型封装类型调用 equals (), 但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,再进行 3 中的比较。
5、对于equal方法来说,如果没有重写过,那么就是相当于==,也就是直接比较地址的,所以呢,如果没有重写equal方法的对象调用equal方法,是直接比较对象地址的。
关于==和equal 还可以看(一)https://blog.csdn.net/qq_33945246/article/details/89922517