创建字符串
//方式1
String str1 = “Hello world”;
//方式2
String str2 = new String("Hello world") ;
//方式3
char[] array = {'a','b','c'};
String str3 = new String(array);
解释:
//String是引用类型
String str = “Hello”;
这样的代码内存布局如下:
**引用解释:**引用类似于C语言中的指针,只是在栈上开辟了一小块内存空间保存一个地址,但和指针不同,指针可以进行各种数字运算(如:指针+1),但引用不能。除此我们也可以将引用想象成一个标签,“贴”到一个对象上,一个对象可以贴一个,也可以贴多个,如果一个对象上一个标签都没有,这个对象就会被JVM当成垃圾对象回收掉。
java中数组,String,以及自定义类型都是引用类型。
下面我们来看下面的代码及内存布局
String str1 = "Hello";
String str2 = str1;
//str1和str2指向同一个对象
在上面的基础上我们再来看下面的代码
str1 = "world";
System.out.println(str2);
// 执行结果 :Hello
//str1只是指向了一个新的string类对象,但是str2的指向还是没有改变。
字符串比较相等
两个int 型的变量可以用==判断其是否相等。但是String呢?
代码1:
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2);
// 执行结果:true
//这个代码中str1和str2指向同一个对象
但是下面的代码比较就出现了问题
代码2:
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2);
// 执行结果:false
//这种方式创建的String对象相当于在堆上另外开辟了空间来存储“Hello”内容,内存中存了两份“Hello”。str1指向一份“Hello”,str2指向一份“Hello”。
所以Java中比较字符串的内容是否相等,要采用equals方法
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// 执行结果:true
equals使用注意事项:
String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
//“Hello”这样的字面值常量,本质上也是一个String对象,
可以用equals等String对象的方法。
字符常量池
(1)直接赋值
String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); //true
System.out.println(str1 == str3); //true
System.out.println(str2 == str3); //true
从上图我们可以看到并没有开辟新的堆内存空间。
这是String类的设计使用了共享设计模式。
**解释:**如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用;如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用。
(2)采用构造方法
String str = new String ("Hello");
这样做有两个缺点:
a. 使用String构造方法会开辟两块堆内存,并且其中一块堆内存会成为垃圾空间(字符常量“Hello”也是一个匿名对象,用了一次之后就不在使用了,就会成为垃圾空间,被JVM自动回收掉)。
b.同一个字符串可能会被存储多次,比较浪费空间。
我们可以使用String的intern方法手动把String对象加入字符串常量池中。
// 该字符串常量并没有保存在对象池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果:false
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果:true
字符串的不可变性
字符串是一种不可变对象,它的内容不可改变。
String类的内部实现是基于Char[]来实现的,但是String类并没有提供set方法之类的来修改内部的字符串数组。
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果:hello world!!!
上面的代码表面上改了字符串,其实并不是。内存变化如下
就我们看到str的结果改变了,但并不是String对象本身发生改变,而是str引用到了其他对象。
如果需要修改字符串,则需要借助原字符串,创建新的字符串。代码如下:
String str = 'Hello";
str = "h" + str.substring(1);
System.out.println(str);
//执行结果:hello