Java—String类型及编译器优化

Java—String类型及编译器优化

我们先来看一道题目:

public class StringTest{
    public static void main(String[] args){
        String str = "xiyou" + "3g" + "backend";
        String str2 = "xiyou3gbackend";
        String str3 = str + "test";
        String str4 = "a" + "b";
        System.out.println(str2 == str);
        System.out.println(str3 == "xiyou3gbackendtest");
        System.out.println(str4 == "ab");
    }
}

这段代码的运行结果为:

《Java—String类型及编译器优化》

这其中涉及到好几个知识点,接下来我们先来介绍String的一些特性

1.String

Java中的String类型并不是基本类型,但是有时候和基本类型差不多,如String b = “tao”;可以对变量直接赋值,而不用new一个对象(当然也可以new)

Java中的变量和基本类型的值存放于栈,而new出来的对象本身存放于堆内存,指向对象的引用还是放在栈内存。例如如下的代码

int i = 1;
String s = new String("Hello World");

此时变量i,常量1,和字符串对象的引用s放在栈内存,而字符串对象 “Hello World”放在堆内存

  • 栈内存的一个特点是:数据共享,这样设计是为了减小内存消耗,在定义了i=1之后,如果再定义一个j=1,此时将j放入栈内存,然后查找占内存中是否有1,如果有则j指向1.如果再给j赋值2,则再栈内存中查找是否有2,如果没有就在栈内存放一个2,然后j指向2。也就是说如果常量在栈内存中,就将变量指向该常量,如果没有就在栈内存中增加一个该常量,并将变量指向该常量

这种基本类型之间比较大小和我们逻辑上判断大小是一致的。如定义i和j都是赋值1,则i==j的结果为true。==用于判断两个变量指向的地址是否一样。既然变量在栈区是数据共享的,那么他们所指的也就是同一个常量,所以地址也是相同的

  • 对于直接赋值的字符串常量(例如:String s = “Hello World”;中的 “Hello World”)也是放在栈区,而new出来的字符串对象是存放在堆内存中。所以如果定义:
String str = "Hello World";
String str2 = "Hello World";

这时 str == str2 就是true。但如果换成:

String str = new String("Hello World");
String str2 = new String("Hello World");

str == str2 就是false了

2.StirngBuilder与StringBuffer

StringBuilder与StringBuffer的用法基本相似,但StringBuffer是线程安全的(所有字符操作的方法被synchronized关键字修饰)。

很多人应该都知道:String是不可变的,我们进行下面的测试

public class StringBuilderTest {
    public static void main(String[] args) {
        String str = "0";
        for (int i = 1; i < 10; i++){
            str += i;
        }
        System.out.println(str);
    }
}

运行结果:

《Java—String类型及编译器优化》

String类确实是不可变的,但在上面的代码里,每次循环执行的str += i; 其实都是新创建了一个String对象,然后再将其引用赋值给str,这样就大大浪费了空间。于是我们出现了StringBuilder

使用StringBuilder完成上述代码:

StringBuilder sb = new StringBuilder("0");
        for (int i = 1; i < 10; i++){
            sb.append(i);
        }
        System.out.println(sb.toString());

输出结果是一样的,但是效率却比上面的代码高很多,因为整个追加过程始终是对一个对象进行操作

编译器对String的优化

从上一段代码中我们可以看到,由于String的不可变性,对其进行操作的效率会大大降低,但对 “+”操作符,编译器也对其进行了优化:

例如执行下面这句:

String temp = "ABC" + 200 + 'D'

等同于:

String temp = new StringBuilder().append("ABC").append(200).append('D').toString();

这样就免于中间创建对象的浪费了

当进行 “+”操作符的 几个对象都是字符串常量

String temp = "ABCD" + "E" + "fg";

编译器也会自动优化为:

String temp = "ABCDEfg";
    原文作者:wintershii
    原文地址: https://blog.csdn.net/wintershii/article/details/81460335
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞