对于Java中String对象的实例化来说,总共有两种实例化方法
直接赋值
String strA = "Hello World";
利用构造方法new
String strB = new String("Hello World");
String对象的实例化比较简单,但是我们这里主要是深入理解其底层的设计以及在内存中的区别,接下来说一下,通过这两种方法实例化的对象有什么不同之处
区别
首先,通过两种不同的方式创建的strA
以及 strB
,测试是否相等
System.out.println(strA == strB);
结果输出为false
原因是对于操作符"=="
来说,进行比较的是数值 也就是说,这时候比较的是在堆内存空间中存放的字符串的地址,显然是不相等的,那么如果我们想要比较的是String对象的内容,需要使用public boolean equals(str)
System.out.println(strB.equals(strA));
此时输出的结果为true
继续分析对于第一种方法的创建来说,是直接在堆内存空间中开辟一块内存,存放Hello World
, 实际上字符串常量相当于是String的匿名对象,所以在栈中有名为strA
的对象指向这块堆内存
而对于第二种方法,内存分析情况为,先是在堆内存空间中开辟内存存放Hello World
,接下来在new
的过程中又在不同的堆内存地址开辟空间并存放Hello World
,而在栈内存空间中的strB
指向的是后面开辟的堆内存空间,这样导致开辟了两块内存空间,那么第一块内存空间就成了我们所谓的垃圾
接下来,假设我们又定义如下对象:
String strC = "Hello World";
那么对于
System.out.println(strA == strC);
结果是true
这是因为,对于直接赋值,这里涉及到共享设计模式 的概念,就是说在JVM的底层设计中有对象池,当创建某个对象时,就会将这个对象的匿名对象入池保存,而后如果有相同的方式创建对象,并且所对应的匿名对象是相同的内容,那么就不会在堆内存中开辟新的内存空间,而是将栈内存中的对象直接指向已有的地址,所以结果为true
对于第二种方式创建的对象,是不会在对象池中保存,如果想要入池,需要手工入池,使用的方法是:public String intern()
String strD = new String("Hello World").intern();
System.out.println(strD == strA);
此时输出的结果为true
总结
综合以上分析,这里只是为了分析比较才有了第二种创建的方法,而在实际工作中是都采用直接赋值的方法。
附
String类中需要记忆的常用方法,持续更新中。。。
方法 | 类型 | 描述 |
---|---|---|
public String(char[] value) | 构造 | 将字符数组转换为String |
public String(char[] value,int offset,int count) | 构造 | 将指定索引区间的字符数组转换为String |
public char charAt(int index) | 普通 | 返回指定索引对应的字符信息 |
public char[] toCharArray() | 普通 | 将字符串以字符数组的形式返回 |
public int lastIndexOf(String str) | 普通 | 由后向前查找指定字符串的位置,找不到返回-1 |
public int lastIndexOf(String str,int fromIndex) | 普通 | 从指定位置由后向前查找字符串的位置,找不到返回-1 |
public boolean startsWith(String prefix) | 普通 | 判断是否以指定的字符串开头,如果是返回true |