String、StringBuffer和StringBuilder的理解
这三个类学过已经有一段时间了,想通过这篇文章再将其复习一下,以求温故知新。
首先说一下三者各自的特性
- String:
- String是不可变类。为什么说是不可变呢,进入String的源码即可知道,String底层维护的是一个数组,而这个数组是用private final修饰的。private说明它是不对外暴露的,final是不可以更改的。
- String的不可变性导致一旦一个String对象被创建后,包含在这个对象中的字符序列是不可以改变的,直至这个对象的销毁。在这里或许有人会提出这样的问题:String s="abc"; s=s+"def"; 这不是字符串明明被改变了嘛,为什么说不可变呢?原因就是:这是两个对象,每次对String类的字符串进行更改就等同于创建了一个新的对象。所以如果会对字符串对象进行频繁的更改,不建议使用String类。
- 创建String对象的两种方法:① String s ="";② String s =new String();
- 再说一种情况:String s1=“hello”;String s2=“world”;String s3=s1+s2;很明显最后s3输出为helloworld。而这是为什么呢?有些人会说是JVM直接在s1后面将s2加上的。但这就违反了String类的不可变性。其实是JVM首先开辟出了一块新的内存区域,然后再将s1和s2复制到这块区域中。这样很明显造成了内存空间的浪费和效率的降低,于是便引出下面将要说明的StringBuilder和StringBuffer。
- 这里再说一个小知识点:
String str1="hello";
String str2="hello";
String str3=new String("hello");
String str4=new String("hello");
①System.out.println("str1==str2?"+(str1==str2)); //true
②System.out.println("str2==str3?"+(str2==str3)); //false
③System.out.println("str3==str4?"+(str3==str4)); //false
④System.out.println("str3.equals(str4)?"+(str3.equals(str4)));//true
String str1="hello"; 这种方式创建字符串的时候,JVM首先会检查字符串常量池中是否存在该字符串的对象,如果已经存在,那么就不会在字符串常量池中再创建了,直接返回该字符串再字符串常量池中的内存地址,如果该字符串对象还不存在在字符串常量池中,那么就会在字符串常量池中先创建该字符串的对象,然后再返回。
String str3=new String("hello");这种方式创建字符串对象的时候,首先JVM先会检查字符串常量池中是否存在“hello”的字符串,如果已经存在,则不会在字符串常量池中创建了,如果还未存在,那么就在字符串常量池中创建“hello”字符串对象,然后还会到堆内存中再创建一份字符串对象,把字符串常量池中的“hello”字符串内容拷贝到堆内存中的字符串对象,然后返回堆内存中的字符串对象的内存地址。
代码①:结果为true,因为创建str2时字符串常量池中已经存在“hello”了,所以就不会再创建了,直接将str1的地址赋给str2。
剩下的②、③、④代码就不作解释了,请自行思考。需要说明的一点就是String类重写了equals()方法。
- StringBuffer:
- 在进行介绍之前先介绍一下Buffer。
- Buffer的意思为缓冲区。就是在内存中有一小块区域,要放什么内容,首先要放在这一小块区域中,然后再准备往其他地方放。就比如说有一个水流很小的水龙头,我们去接水都是用桶等容器去接,接满后再将桶中的水倒入其他地方。而这个桶就相当于一个缓冲区。
下面开始StringBuffer的正文:
- StringBuffer代表的是一个字符序列可变的字符串。当一个StringBuffer对象被创建以后,通过StringBuffer提供的append()、insert()、reverse()等方法,就可以改变这个字符串对象的字符序列。
- StringBuffer底层维护的是一个字符数组。如果使用无参构造方法,这个字符数组的默认初始容量为16。 如果长度不够用,就自动增长为原来的两倍加2。
- 一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
- StringBuffer是线程安全的,操作效率低。所谓线程安全是指在一个时间段内只允许一个线程来操作这份代码。
- StringBuilder:
- StringBuilder类也代表了字符串对象,和StringBuffer基本相似。
- StringBuilder是线程非安全的,操作效率高。所谓线程不安全指在一个时间段内一个代码可以由多个线程同时来执行。
- 总结:如果对字符串操作的少就用String,否则每次操作字符串都会产生一个新的对象,内存会吃不消的。如果单线程就用StringBuilder,因为StringBuilder是并没有实现线程安全,但是操作效率高。如果是多线程就使用StringBuffer,因为StringBuffer是线程安全的。
以上内容为自己整理的所学到的知识,当然还有很多不足,这需要您的指出。其中还有很多知识点没有列出,毕竟知识点太多了,越学习就越发现知识的海洋的广阔以及自己的渺小与无知,自己需要学的东西还非常多。路漫漫其修远兮,吾将上下而求索。