• String、StringBuiler、StringBuffer的区别


    一、三者的区别概述

      1.可变与不可变:String底层使用final修饰的字符数组来存储字符串,它属于不可变类,对String对象的任何改变操作都不会改变原对象,而是生成一个新对象。StringBuilder和StringBuffer有一个共同的抽象父类AbstractStringBuiler,它们底层是一个不用final修饰的字符数组,因此它们是可变的。

       2.是否线程安全:String由final修饰,因此必然是线程安全的。StringBuilder与StringBuffer的唯一区别就是StringBuffer的方法都加上了syncharnized,因此StringBuffer是线程安全的。

          3.执行效率:StringBuilder > StringBuffer > String

    二、对String的深入剖析

    1.String str="hello world"和String str=new String("hello world")的区别

    private static void test1() {
            String str1 = "hello world";
            String str2 = new String("hello world");
            String str3 = "hello world";
            String str4 = new String("hello world");
    
            System.out.println(str1==str2);
            System.out.println(str1==str3);
            System.out.println(str2==str4);
        }

    运行结果:

    false
    true
    false

    在class文件中有一部分用来存储编译期生成的字面常量以及符号引用,这部分叫做class文件的常量池,在运行期间对应着方法区的运行时常量池。上面代码中str1,str2在编译期间都会生成字面常量和符号引用,运行时会将字面常量保存在方法区的运行时常量池,只保存一份,将引用和对象进行绑定时会检查常量池中是否存在相同的字面常量,有则直接绑定,没有则新建,因此可知str1,str2指向的是同一个字面常量,而new操作是在堆区新建对象,肯定是产生了新的对象。

    2.

    private static void test2() {
            String a = "hello2";
            String b = "hello" + 2;
            System.out.println((a == b));
        }

    运行结果:true

    在编译期"hello" + 2被优化为hello2,因此a,b指向的是同一个对象。

    3.

    private static void test3() {
            String a = "hello2";
            String b = "hello";
            String c = b + 2;
            System.out.println((a == c));
        }

    运行结果:false

    由于存在符号引用,b+2并不会被编译器优化,只有处理字面常量时才会有优化。因此c,a是两个不同的对象。

    4.

    private static void test4() {
            String a = "hello2";
            final String b = "hello";
            String c = b + 2;
            System.out.println((a == c));
        }

    运行结果:true

    由于b被final修饰,属于一个常量,编译器会进行优化,对final变量的访问在编译期间都会直接被替代为真实的值,因此c = "hello" + 2。

    5.

    public class Main {
        public static void main(String[] args) {
            String a = "hello2";
            final String b = getHello();
            String c = b + 2;
            System.out.println((a == c));
        }
         
        public static String getHello() {
            return "hello";
        }
    }

    运行结果:false

    b虽然被final修饰,但它的值只有在运行期间才能确定,因此编译器不会优化。a,c指向不同的对象。

    6.

    public class Main {
        public static void main(String[] args) {
            String a = "hello";
            String b =  new String("hello");
            String c =  new String("hello");
            String d = b.intern();
             
            System.out.println(a==b);
            System.out.println(b==c);
            System.out.println(b==d);
            System.out.println(a==d);
        }
    }

    运行结果:

    false
    false
    false
    true

    在String类中,intern方法是一个本地方法,在JAVA SE6之前,intern方法会在运行时常量池中查找是否存在内容相同的字符串,如果存在则返回指向该字符串的引用,如果不存在,则会将该字符串入池,并返回一个指向该字符串的引用。因此,a和d指向的是同一个对象。

    7.String str = new String("abc")创建了多少个对象?

    创建了一个对象,涉及到两个对象。在类加载的过程中,在运行时常量池中创建了一个"abc"对象,而在代码执行过程中只创建了一个String对象。

    8.

    public class Main {
        public static void main(String[] args) {
            String str1 = "I";
            //str1 += "love"+"java";        1)
            str1 = str1+"love"+"java";      //2)
             
        }
    }

    1)的效率比2)的效率要高,1)中的"love"+"java"在编译期间会被优化成"lovejava",而2)中的不会被优化。

    个人总结:编译器是否会在编译期优化取决于取决于这个"常量"在编译期是否是一个确定的值,以及它是否是一个字面常量,如果存在引用符号则不会优化。

    参考链接:https://www.cnblogs.com/dolphin0520/p/3778589.html

         https://www.cnblogs.com/xudong-bupt/p/3961159.html

  • 相关阅读:
    Ubunut16.04 安装 Theano+GPU
    ubuntu源与常用python配置pip源(win)、pip常用命令
    集群(heartbeat)搭建
    Linux下搭建企业共享目录方案之------samba
    LAMP的安装和注意事项
    Linux最小化安装,忘记安装开发工具的解决方法
    去掉Linux尖锐的提示音
    最小化安装CentOS7,没有ifconfig命令---yum search command_name搜索未知包名
    编译安装php-5.4.44
    configure: error: Please reinstall the libcurl distribution
  • 原文地址:https://www.cnblogs.com/jxxblogs/p/11027901.html
Copyright © 2020-2023  润新知