Java内存主要分为堆内存,栈内存,方法区
在Java1.6以及之前,常量池是放在方法区的,方法区里面的东西很少进行GC,一般称为持久代
在Java1.7以及之后,常量池是放在堆区的,堆区主要存储新建的对象,占用内存最大
常量池中存放所有byte类型范围的变量,即(-128到127中的所有的值)、直接定义的字符串变量、用final或static定义的变量。
①在常量池中创建字符串对象
String str1 = "constent";
此语句代表在常量池创建了一个 内容为constent的字符串对象
String str2 = "constent"
此语句的字符串对象内容也为“constent”,常量池中已经存在,那么就不会再次创建,只是将引用指向已经创建了的字符串对象
System.out.println(str1 == str2);
使用==判断对象的时候判断的是两个对象的引用是否相同,此时两个字符串对象在内存中是一个,两个引用都是指向这个字符串对象,所以此时返回ture
②在堆内存中创建字符串对象
String str3 = new String("1");
此方法是在堆内存中新创建一个对象str3
String str4 = new String("1"); System.out.println(str3 == str4);
str4也是从堆内存中新建的对象,虽然内容相同,但是是新创建的对象,与在常量池中不同。此时使用==来判断两个对象是否相等,因为是不同的对象,所以也是不同的引用,结果为false
③equal方法
System.out.println(str3.equal(str4));
此时equal方法是去判断两个字符串对象的内容是否相同,所以上述语句返回true
在Java中变量分为基本类型和引用类型,
使用==判断基本类型(8种)是否相等,是判断变量的值
使用==判断引用类型变量是否想等,是判断变量的引用是否相等
equal方法本质也是使用==,Integer类和String类提供了equal方法判断其对象的内容是否相同,在equal方法内部,是将对象的内容转换为基本数据类型,使用==进行比较的。
④intern方法
String str5 = new String("hello");
String str6 = new String("hello");
System.out.println(str5.intern() == str6.intern());
我们可以使用intern方法判断两个字符串的值是否相等,intern方法返回一个在Java常量池中的和当前字符串对象相同内容的对象。
因为在Java常量池中内容相同的字符串对象只会创建一次,当再有相同内容的字符串对象是将引用直接指向这个已经存在的对象,这样两个字符串对象比较是否相等,就可以直接比较引用,实现了两个字符串对象直接用==比较值,而不是用equal.
Java源码中intern方法注释:@return a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings
注:无论是把常量池放在方法区还是堆内存中,intern方法都是要在常量池拿到一个独一无二的变量,如果没有则创建,有则指向它。
String s3 = new String("1") + new String("1");
此语句中,新建的内容为“1”字符串变量在堆内存中,合成后的“11”也在堆内存中。
⑤Integer对象
定义的Integer对象,值范围在-128到127中时,可以直接使用==来判断是否相等,因为Java虚拟机在启动的时候会将-128到127中的所有值都进行初始化,所以定义一个此范围的对象,只是将对象的引用直接指向已经创建好的对象。
Integer a = 128;
Integer b = 128;
System.out.println(a == b);
当值的范围大于等于128或者小月等于-129时,创建Integer类型的对象则会在堆内存中创建新的对象,此时使用==进行比较,因为引用不同,所以虽然对象的内容是相同的,但是对比返回false
此时可以使用equal或者intern方法进行比较。