zoukankan      html  css  js  c++  java
  • 【JAVA

    本文主要解决以下几个问题

    • String源码解析?
    • String和new String的区别?
    • String通过“+”或concat累加时的对象创建机制?
    • StringBuilder和StringBuffer?区别和联系?

    String源码解析

    String类的定义

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence { ...... }
    

    通过上面的代码可以得出以下结论:

    • String类使用final关键字修饰,表示String类是最终类,不可以被继承;
    • String类是CharSequence的一个实现类;
    • String类实现了Serializable接口,表示String类可以被序列化;
    • String类实现了Comparable接口,表示String类对象之间可以直接进行比较

    String#value

    /** The value is used for character storage. */
    private final char value[];
    
    • String中的value属性用于字符存储;
    • String中的value属性使用final关键字修饰,表示value不可变

    由于value不可变,因此,String对象具有以下两个特点:

    • String对象地址不可变(Immutable)
    • String对象是线程同步的(can be shared)

    String#concat()

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
    

    不管上面对字符串进行了什么处理,只看最后一行,返回了一个new String,因此,concat()方法实际上是返回了一个新的字符串。也就是说,每次调用concat()方法时,concat()方法中的参数会生成一个新的字符串变量,执行后得到的新字符串又是一个新的字符串变量。使用“+”进行字符串累加时也是一样的机制。

    String和new String的区别

    Java虚拟机中用于存储的区域分为栈、堆和方法区,方法区中包括另一片区域,称为常量池。String的存储主要涉及到的存储区域就是堆、栈和常量池。

    栈中主要存储的是简单类型的变量和引用类型变量的存储地址;堆中存储的是引用类型数据本身;常量池中存储的是常量。

    String变量的声明和定义方式有两种:

    • String str1 = new String("mystr");
    • String str2 = "mystr";

    以上两种创建String对象的方式的区别是:

    • 运行时机的不同:第一种方式中有new关键字,是在程序运行期间才会执行的;而第二种方式是在编译期间就执行了;
    • 创建对象过程的不同:使用第一种方式创建String对象时,首先在堆中创建一个String对象,然后在栈中开辟一片空间,指向堆中的这一片区域,最后去常量池中寻找是否存在这个字符串常量,如果不存在,则在常量池中创建一个;使用第二种方式创建String对象时,会直接去常量池中寻找是否有这个字符串常量,如果有则直接引用到栈中,如果没有则先创建一个再引用到栈中。
    • 通过上一点可以得出结论:通过第一种方式创建String对象之后,在堆中、常量池中分别有一个对象,因此是创建了一个或两个对象;通过第二种方式创建String对象之后,在常量池中有一个对象,因此是创建了零个或一个对象;
    • 使用第一种方式,栈中的指针指向的是堆中的对象;使用第二种方式,栈中的指针指向的是常量池中的对象

    StringBuilder和StringBuffer

    前面说到,使用“+”和concat()方法对字符串进行拼接的时候,会创建额外的字符串变量,因此,当我们需要进行字符串拼接的时候,比较提倡的方法是使用StringBuilder或StringBuffer。

    StringBuilder和StringBuffer中都提供了append()方法,可以实现字符串的拼接。

    public final class StringBuffer
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    
    public final class StringBuilder
        extends AbstractStringBuilder
        implements java.io.Serializable, CharSequence
    

    StringBuilder和StringBuffer都继承自AbstractStringBuilder,其底层依然是一个char数组,但不是final类型的。

    // StringBuffer # append()
    public synchronized StringBuffer append(CharSequence s) {
        toStringCache = null;
        super.append(s);
        return this;
    }
    
    // StringBuilder # append()
    public StringBuilder append(CharSequence s) {
        super.append(s);
        return this;
    }
    

    从上面的StringBuffer和StringBuilder的append()方法的源码比较中可以发现,两个类中append()方法唯一的区别就是,StringBuffer中的append()方法添加了synchronized关键字,表示这个方法是线程同步的。

    通过上面的分析得到结论:StringBuffer是线程安全的,而StringBuilder是线程不安全的。

    由于StringBuilder是线程不安全的,因此StringBuilder处理字符串的性能要比StringBuffer高。

  • 相关阅读:
    Educational Codeforces Round 20 A. Maximal Binary Matrix(模拟)
    SCU 4440 Rectangle (思维+暴力)
    poj 2799 IP Networks (模拟/水题)
    Uva 10629 Huge Mods (指数循环节)
    FUZ 1759 Super A^B mod C (指数循环节/模板)
    Uva 11149 Power of Matrix (倍增法/模板)
    poj 3863&&Gym
    Codeforces 392C Yet Another Number Sequence (矩阵快速幂+二项式展开)
    Uva 11029 Leading and Trailing (求n^k前3位和后3位)
    Uva 10006 Carmichael Numbers (快速幂)
  • 原文地址:https://www.cnblogs.com/itgungnir/p/8242466.html
Copyright © 2011-2022 走看看