字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。
Java 可以通过最简单的String str = "this is string"
,来创建字符串;
也可以通过构造函数创建字符串String str2 = new String("this is string")
来创建字符串。
两者的区别
首先明白一个事,java存在一个常量池,可以用来存储字符串常量。先知概念:
①【常量池constant pool】管理在编译时被确定并保存在已编译的.class文件中的一些数据,包括关于类、方法、接口中的常量,和字符串常量。
②【字符串常量池(String pool, String intern pool, String保留池)】 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
当使用new String(“hello”)
时,JVM会先使用常量池来管理“hello”直接量,再调用String类的构造器来创建一个新的String对象,新创建的对象被保存在堆内存中。即new String(“hello”)
一共产生了两个字符串对象。
问题:
//代码1
String sa=new String("Hello world");
String sb=new String("Hello world");
System.out.println(sa==sb); // false
//代码2
String sc="Hello world";
String sd="Hello world";
System.out.println(sc==sd);
// true
JVM为了提升性能和减少内存开销,避免字符串的重复创建,维护了一块特殊的内存空间——字符串常量池。
String赋值的两种方式。
1、String str = "test";
以这种方式赋值时,JVM会先从字符串常量池中查询是否存在"test"这个对象,
如果存在,直接把常量池中"test"的地址返回给str。如果不存在,则会在常量池中创建"test"对象,并把该对象的地址返回给str。
所以通过==比较是,str1,str2指向的是同一地址,所以返回true;
2、String str = new String("test");
以这种方式赋值时,JVM会先从字符串常量池中查询是否存在"test"这个对象,
若不存在则会在常量池中创建"test"对象,同时调用String类的构造器在堆中创建"test"这个对象,然后将堆中的这个对象的地址返回赋给引用str。
若常量池存在则直接调用String类的构造器在堆中创建"test"这个对象,然后将堆中的这个对象的地址返回赋给引用str。
这时str1和str2分别指向堆中不同的地址,所以返回false;
String为什么是不可变的?
答:最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类型? 不可变对象,顾名思义就是创建后不可以改变的对象,典型的例子就是Java中的String类。
String s = "ABC"; s.toLowerCase();
如上s.toLowerCase()并没有改变“ABC“的值,而是创建了一个新的String类“abc”,然后将新的实例的指向变量s。 相对于可变对象,不可变对象有很多优势:
1).不可变对象可以提高String Pool的效率和安全性。如果你知道一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小)需要很小的内存效率也很高。对于同时引用这个“ABC”的其他变量也不会造成影响。
2).不可变对象对于多线程是安全的,因为在多线程同时进行的情况下,一个可变对象的值很可能被其他进程改变,这样会造成不可预期的结果,而使用不可变对象就可以避免这种情况。 当然也有其他方面原因,但是Java把String设成immutable最大的原因应该是效率和安全。
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
运行速度快慢为:StringBuilder > StringBuffer > String
总结
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况