目录
(1)System.identityHashCode()查询对象的引用地址:
一、String深入:编译期和运行期
1.简单阐述:
在编译时,如果碰到了String s = "hello"; 这样的赋值方式,就是字面量形式赋值,编译时就直接编译成 String s = "hello"; ,然后拿到内存中时就按照上述所说的直接赋值的那种方式去赋值,str3 = "abc" + "d"其实就等同于字面量赋值(即等同于str3 = "abcd")。但是,如果是str2这种赋值方式String str2 = str + "d"; ,虽然str在上面已经定义了,但是在编译时认为str仍是一个引用类型变量,所以此时就会把str2认为是以new String()方式来创建的,等来到内存中呢,就按照new String()这种方式去创建str2,自然堆内存中就会开辟空间,然后创建对象,接着再把空间的地址值返回给str2。所以str1和str2并没有指向同一个对象,地址值自然不同,这同时也解释了提出的问题。
2.代码例子:
(1)System.identityHashCode()查询对象的引用地址:
System.identityHashCode()方法间接查询真实的地址
似乎String.hashCode()方法返回的是处理过的地址???
String str = "abc";//在常量池中创建abc
String str1 = "abcd";//在常量池中创建abcd
String str2 = str+"d";//拼接字符串,此时会在堆中新建一个abcd的对象,因为str2编译之前是未知的
String str4 = str1;//由于并没有拼接运算,直接将str1的引用地址传递给str
String str3 = "abc"+"d";//拼接之后str3还是abcd,所以还是会指向字符串常量池的内存地址
System.out.println(str1==str2);//false
System.out.println(str1==str4);//True
System.out.println(str1==str3);//true
public class StringBy
{
public static void main(String[] args){
//情况一
String a = "a2";
String a2 = "a"+2;
//在编译期值是确定的就是a2。只有编译期变量a与变量a2值相等他们才相等
System.out.println(a==a2);
//情况二
String b = "b2";
int bb = 2;
String b2="b"+bb;
//在编译期变量b2的值不是确定的,因为bb是变量,变量在运行期才能确定值.所以b与b2不等
System.out.println(b==b2);
//情况三
String c="c2";
final int cc=2;
String c2="c"+cc;//在编译期c2的值是确定的,因为cc是个常量,值为2
System.out.println(c==c2);
//情况四
String d="d2";
final int dd=getZ();
String d2="d"+dd;
//在编译器d2的值是不确定的,因为dd还没有确定,因为dd的值是靠方法返回来的,但是方法的结果是在
//运行期才能得到的
System.out.println(d==d2);//(对于两个对象,==的作用是比较他们的地址。)
}
public static int getZ(){
return 2;
}
}
二、String和StringBuffer的区别:
1.可变与不可变:
String:长度固定
StringBuffer:长度可变
StringBuilder:长度可变
2.初始化方式:
String:直接赋值和new开辟
StringBuffer:new开辟
StringBuilder:new开辟
3.字符串修改方式:
String:由于长度不可改变,修改时相当于创建StringBuffer对象并调用append()方法,最后toString()将引用地址返回给String,堆中将会产生无引用指向的垃圾冗余,冗余到一定程度,JVM会启用垃圾清理,造成性能下降。
StringBuffer:直接在该字符串后边加,不改变引用。
4.equals()方法:
String中的equals方法进行了重写:比较的是字符串的内容
StringBuffer中未对equals方法进行重写:比较的是引用地址
5.线程安全性:
StringBuffer与StringBuilder都提供了一系列插入、追加、改变字符串里的字符序列的方法,它们的用法基本相同,只是StringBuilder是线程不安全的,StringBuffer是线程安全的,。如果只是在单线程中使用字符串缓冲区,则StringBuilder的效率会高些,但是当多线程访问时,最好使用StringBuffer。
三、文章参考:
(1条消息) Java:String类型为什么可以直接赋值?使用new String赋值不可以吗?_@阿证1024的博客-优快云博客_string为什么可以直接赋值
深入理解String、StringBuffer和StringBuilder类的区别 - 腾讯云开发者社区-腾讯云 (tencent.com)