1. 字符串类Java的底层实现的类,final修饰安全考虑
字符串本质是一个常量。(一旦被初始化在内存中只有一份)
字符串缓冲池:字符串常量池(保证了字符串只有一份)
2. 面试题:java中字符串常量池在什么地方?
jdk7之前,字符串常量池在方法区(方法区还有类的信息,小整形缓冲池,静态属性,方 法,引用)
jdk7之后,字符串常量池被设计到了堆内存中(小整形缓冲池,静态 被挪到了元数据区)
3. 字符串创建方式:
String s = "Jack"; // 这种方式创建字符串(先从常量池找Jack,找到了则返回 Jack这个单词的引用;若找不到,则在常量池中初始化字符串,再将地址返回给s)
String ss = new String("Jack"); //会创建一个堆内存
4. 面试题:下面这段代码会创建几个字符串对象
String s = "ljh"//有可能创建一个,有可能不创建
String ss = new String("ljh")//有可能创建一个,有可能创建两个
5. 字符串拼接问题:
字符串拼接时,如何判断拼接后的结果是否相等(==)
|-- 常量始终是常量
|-- 编译时,如果结果确定,则会相等??
- package com.openlab.day15;
-
- import org.junit.jupiter.api.Test;
-
- public class TestString {
-
- @Test
- void test01() {
- String s = "hello";
- String ss = "hello";
- System.out.println(s == ss);
- }
-
- @Test
- void test02() {
- String s = "hello";
- String ss = new String("hello");
- System.out.println(s == ss);
- }
-
- @Test
- void test03() {
- String s = "hello";
- String ss = "world";
- String sss = "helloworld";
- System.out.println(s + ss);
- System.out.println(s + ss == sss);
- }
-
- @Test
- void test04() {
- String s = "hello";
- String ss = "world";
- final String sss = "helloworld";
- System.out.println(s + ss == sss);
- }
-
-
- }
- package com.openlab.demo;
-
- import org.junit.jupiter.api.Test;
-
- class Test01 {
-
- @Test
- void test01() {
- String s1 = "hello";
- final String s2 = "hello";
- String ss = new String("hello");
- String s3 = "hello2";
-
- String s4 = s1 + 2;
- String s5 = s2 + 2;
-
- System.out.println(s1 == s2);
- System.out.println(s1 == ss);
- System.out.println(s2 == ss);
-
- System.out.println(s3 == s4);
- System.out.println(s3 == s5);
- }
-
- }
因为字符串是常量,字符串在大量拼接,容易产生垃圾数据。
字符串是一种常量,一旦产生一个字符,如果常量池中,不存在这个字符串,则会将这个字 符串保存常量池(这个保存时永久性的、只有系统退出才会被销毁)
字符串不像其他变量,如int a = 10,当后面不用会自动回收,而字符串是常量,无法被回收
因此在开发过程中,一定注意,不要大量拼接字符串,以避免产生大量无用的字符串消耗内存
java为了解决这个问题,引入了两个字符串操作类:StringBuffer和StringBuilder
- void test06() {
- //拼接字符串 123456789101112...99100
- String s = "";//存在常量池
- for(int i = 1; i <= 100; i++) {
- s += i;
- //会产生很多的字符串"1" "12" "123"..."123...99" "123...99100"
- //但我们需要的只是最后一个字符串,但在此过程中产生了很多没有用的字符串
- }
- System.out.println(s);
- }
1. java提供给用来操作字符串的两个工具类,和字符串没有关系
是两个对象,不是常量,可以借助这两个对象对字符串进行拼接,因为在拼接过程中产生的 临时变量没有变量保存就消失了。如下面的for循环
for(int i = 0; i < 100; i++){
System.out.println(i);
}
//每次都赋给了i变量,最终只有一个变量i,其他99个在循环的过程中都舍弃了,因为不是常量,所以一旦创建不用,就自动回收了,不像字符串,是常量,一旦产生会加载到常量区,出不去,gc都没有用
这两个对象都是jdk底层提供用来拼接大量字符串从对象,不会产生大量无用常量,替代字符串的大量拼接,提高效率。
- @Test
- void testStringBuffer() {
- StringBuffer buffer = new StringBuffer();//不写也是空空
- //或者StringBuffer buffer = new StringBuffer("");
- for(int i = 1; i <= 100; i++) {
- buffer.append(i);//在尾部添加
- //buffer.insert(0, i);//也可以向其他位置添加
- }
- System.out.println(buffer.toString());
- System.out.println(buffer);
- }
-
- @Test
- void testStringBuilder() {
- StringBuilder builder = new StringBuilder();//不写也是空空
- //或者StringBuffer buffer = new StringBuffer("");
- for(int i = 1; i <= 100; i++) {
- builder.append(i);
- }
- System.out.println(builder.toString());
- System.out.println(builder);
- }
2. 两个用法一样,都会输出:
(太长,一张显示不下)
3. StringBuffer和StringBuilder 区别:
1).StringBuffer:
所有操作方法上加上了同步锁,所以是线程安全的
synchronized:同步
如:append()方法
2).StringBuilder:
没有加同步锁,因此非线程安全的!!!
一般情况下建议使用StringBuilder,效率更高(不加锁效率高)
但是不加锁在高并发,多线程情况下可能会出现线程安全问题,用StringBuffer(但是在这种情况下很少用字符串,所以还是StringBuilder用的更多一点)