Hefery 的个人网站

Hefery's Personal Website

Contact:hefery@126.com
  menu
73 文章
0 浏览
0 当前访客
ღゝ◡╹)ノ❤️

Java基础—String

String

String特点

  • String 被 final 修饰,不可被继承,并且它的成员方法都默认为 final 方法
  • String 通过 char 数组存储字符数据
    String str = "abc";
     等效于: 
    char data[] = {'a', 'b', 'c'};
    String str = new String(data);
    

String源码

成员变量

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

     /** 字符存储 */
    private final char value[];

    /** 缓存字符串的哈希代码 */
    private int hash; // Default to 0

}

构造方法

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

    /**
     * 初始化新创建的 String 对象(空字符序列)
     * 由于字符串是不可变的,因此不需要使用此构造函数
     * @return [description]
     */
    public String() {
        this.value = "".value;
    }

    /**
     * 初始化的字符串是参数 original 字符串的副本
     * @param  original [description]
     * @return          [description]
     */
    public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

    /**
     * 将 value[] 分配到 String
     * 对字符数组的后续修改不会影响新创建的字符串
     * @param  value[] [description]
     * @return         [description]
     */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

    /**
     * 从 codePoints[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
     * 对字符数组的后续修改不会影响新创建的字符串
     * @param  value[] 作为字符源的数组
     * @param  offset  初始偏移量,子数组第一个字符的索引
     * @param  count   子数组的长度
     * @return         [description]
     */
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= value.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

    /**
     * 创建编码格式为 Unicode,从 codePoints[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
     * @param  codePoints Unicode code Points 数组
     * @param  offset     初始偏移量,子数组第一个字符的索引
     * @param  count      子数组的长度
     * @return            [description]
     */
    public String(int[] codePoints, int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count <= 0) {
            if (count < 0) {
                throw new StringIndexOutOfBoundsException(count);
            }
            if (offset <= codePoints.length) {
                this.value = "".value;
                return;
            }
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > codePoints.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }

        final int end = offset + count;

        // Pass 1: Compute precise size of char[]
        int n = count;
        for (int i = offset; i < end; i++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                continue;
            else if (Character.isValidCodePoint(c))
                n++;
            else throw new IllegalArgumentException(Integer.toString(c));
        }

        // Pass 2: Allocate and fill in char[]
        final char[] v = new char[n];

        for (int i = offset, j = 0; i < end; i++, j++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                v[j] = (char)c;
            else
                Character.toSurrogates(c, v, j++);
        }

        this.value = v;
    }

    /**
     * 创建编码格式为 ascii,从 ascii[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
     * @param  ascii[] ascii[] 数组
     * @param  hibyte  [description]
     * @param  offset  初始偏移量,子数组第一个字符的索引
     * @param  count   子数组的长度
     * @return         [description]
     */
    @Deprecated
    public String(byte ascii[], int hibyte, int offset, int count) {
        checkBounds(ascii, offset, count);
        char value[] = new char[count];

        if (hibyte == 0) {
            for (int i = count; i-- > 0;) {
                value[i] = (char)(ascii[i + offset] & 0xff);
            }
        } else {
            hibyte <<= 8;
            for (int i = count; i-- > 0;) {
                value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
            }
        }
        this.value = value;
    }

    @Deprecated
    public String(byte ascii[], int hibyte) {
        this(ascii, hibyte, 0, ascii.length);
    }

    /**
     * 创建编码格式为 charsetName,从 bytes[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
     * @param  bytes[]                      要解码为字符的字节
     * @param  offset                       要解码的第一个字节的索引
     * @param  length                       要解码的字节数
     * @param  charsetName                  支持的 ava.nio.charset.charset 名称
     * @return                              [description]
     * @throws UnsupportedEncodingException 如果不支持命名字符集
     */
    public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException {
        if (charsetName == null)
            throw new NullPointerException("charsetName");
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(charsetName, bytes, offset, length);
    }

    public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);
    }

    /**
     * 将 bytes[] 转化为编码格式为 charsetName 的 String 类
     * @param  bytes[]                      [description]
     * @param  charsetName                  [description]
     * @return                              [description]
     * @throws UnsupportedEncodingException [description]
     */
     public String(byte bytes[], String charsetName) throws UnsupportedEncodingException {
        this(bytes, 0, bytes.length, charsetName);
    }

    public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }

    /**
     * 创建默认编码格式 ISO-8859-1,从 bytes[] 的索引为 offset 开始截取长度为 length 的子串为 String 类 
     * @param  bytes[] [description]
     * @param  offset  [description]
     * @param  length  [description]
     * @return         [description]
     */
    public String(byte bytes[], int offset, int length) {
        checkBounds(bytes, offset, length);
        this.value = StringCoding.decode(bytes, offset, length);
        // String csn = Charset.defaultCharset().name(); ...
        // return decode("ISO-8859-1", ba, off, len); ...
    }

    /**
     * 创建默认编码格式 ISO-8859-1 为 String 类 
     * @param  bytes[] [description]
     * @return         [description]
     */
    public String(byte bytes[]) {
        this(bytes, 0, bytes.length);
    }

    /**
     * 将 StringBuffer 转化为 String
     * @param  buffer [description]
     * @return        [description]
     */
    public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

    /**
     * 将 StringBuilder 转化为 String
     * @param  builder [description]
     * @return         [description]
     */
    public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }

    /**
     * share 提升速度
     */
    String(char[] value, boolean share) {
        // assert share : "unshared not supported";
        this.value = value;
    }

}

字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池 。创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于 String 字符串的不可变性,可以十分肯定常量池中一定不存在两个相同的字符串

public class stringDemo {
    public static void main(String[] args) {
        String str0 = "abc";
        String str1 = "abc";
  
        String str2 = new String();

        char[] charArray = { 'a', 'b', 'c' };
        String str3 = new String(charArray);

        byte[] byteArray = { 97, 98, 99 };
        String str4 = new String(byteArray);

        // 字符串引用比较
        System.out.println(str0 == str1);  // true
        System.out.println(str0 == str3);  // false
        System.out.println(str0.equals(str3));  // true

        // 字符串比较
        String str5 = null;
        System.out.println("abc".equals(str5));   // 推荐
        System.out.println(str5.equals("abc"));   // NullPointerException

        String strA = "JAva";
        String strB = "java";
        System.out.println(strA.equalsIgnoreCase(strB));    //忽略大小写
    }
}

成员方法

类型方法说明
获取
charcharAt(int index)返回指定索引处的 char 值
intindexOf(int ch)返回指定字符在此字符串中第一次出现处的索引
booleancontains(CharSequence s)当且仅当此字符串包含指定的 char 值序列时,返回 true
booleanendsWith(String suffix)测试此字符串是否以指定的后缀结束
booleanstartsWith(String prefix)测试此字符串是否以指定的前缀开始
booleanmatches(String regex)告知此字符串是否匹配给定的正则表达式
intlength()返回此字符串的长度
booleanisEmpty()length() 为 0 时返回 true
booleanequalsIgnoreCase(String anotherString)将此 String 与另一个 String 比较,不考虑大小写
操作
Stringconcat(String str)尾插法连接字符串
byte[]getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中
String[]split(String regex)根据给定正则表达式的匹配拆分此字符串
Stringsubstring(int beginIndex, int endIndex)返回一个新的字符串,它是此字符串的一个子字符串
StringtoLowerCase()使用默认语言环境的规则将此 String 中的所有字符都转换为小写
StringtoUpperCase()使用默认语言环境的规则将此 String 中的所有字符都转换为大写
Stringtrim()返回字符串的副本,忽略前导空白和尾部空白
intcompareTo(String anotherString)按字典顺序比较两个字符串
booleanequals(Object anObject)将此字符串与指定的对象比较
inthashCode()返回此字符串的哈希码
char[]toCharArray()将此字符串转换为一个新的字符数组
StringtoString()返回此对象本身
static StringvalueOf(T t)返回 T 参数的字符串表示形式

String Q&A

String 和 int 转换

  • String 转 int:Integer.valueOf("str")、Integer.PaseInt(str)
  • int 转 String:String.valueOf(12)、12 + ""

equals和==

  • ==:
    • 基本数据类型变量,比较其存储的值是否相等
    • 引用类型变量,比较所指向的对象地址(即是否指向同一个对象)
  • equals:比较指向对象的内容是否相同,不能作用于基本数据类型的变量
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}

String相关的+

String 中使用 + 字符串连接符进行字符串连接时,连接操作最开始时如果都是字符串常量,编译后将尽可能多的直接将字符串常量连接起来,形成新的字符串常量参与后续连接。接下来的字符串连接是从左向右依次进行,对于不同的字符串,首先以最左边的字符串为参数创建 StringBuilder 对象,然后依次对右边进行 append操作,最后将 StringBuilder 对象通过 toString() 方法转换成 String 对象(注意:中间的多个字符串常量不会自动拼接)

String c = "xx" + "yy " + a + "zz" + "mm" + b; 
实现过程: 
String c = new StringBuilder("xxyy ").append(a).append("zz").append("mm").append(b).toString();

当使用+进行多个字符串连接时,实际上是产生了一个StringBuilder对象和一个String对象

StringBuffer

StringBuffer特点

  • 字符串的缓冲区(缓冲区可变长度),是一个容器,和 String 类不同的是,StringBuffer 类的对象能够被多次的修改,并且不产生新的未使用对象

StringBuffer源码

构造方法

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

    /**
     * 构造一个空的 StringBuffer 对象,初始容量为16个字符
     * @return StringBuffer对象
     */
    public StringBuffer() {
        super(16);
        // bstractStringBuilder(int capacity) { value = new char[capacity]; }
    }

    /**
     * 构造一个空的 StringBuffer 对象,初始容量为 capacity
     * @param  capacity 初始容量
     * @return          StringBuffer对象
     */
    public StringBuffer(int capacity) {
        super(capacity);
    }

    /**
     * 构造一个空的 StringBuffer 对象,初始容量为 str.length() + 16
     * @param  str [description]
     * @return     StringBuffer对象
     */
    public StringBuffer(String str) {
        super(str.length() + 16);
        append(str);
    }

    /**
     * 构造一个包含与指定的 CharSequence 相同字符的空 StringBuffer 对象,初始容量为 seq.length() + 16
     * @param  seq [description]
     * @return     StringBuffer对象
     */
    public StringBuffer(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

}

成员方法

类型方法说明
StringBufferappend(T t)添加各种类型的数据
StringBufferinsert(int offset, T t)在容器指定位置插入各种类型的数据
StringBufferdeleteCharAt(int index)删除指定位置的字符
StringBufferdelete(int start, int end)移除此序列的子字符串中的字符
StringBufferreplace(int start, int end, String str)替换
charcharAt(int index)获取指定索引处的 char 值
intlength()元素个数
intcapacity()当前容量
intindexOf(String str)返回第一次出现指定子字符串在该字符串的索引
intlastIndexOf(String str)返回最右边出现指定子字符串在此字符串的索引
Stringsubstring(int start)截取
Stringsubstring(int start, int end)返回包含此字符序列当前所包含字符子序列
StringBufferreverse()反转
StringtoString()返回此序列中数据的字符串表示形式

StringBuilder

StringBuilder特点

StringBuilder源码

构造方法

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

    /**
     * 构造一个不带任何字符的 StringBuilder 对象,其初始容量为 16 个字符
     * @return StringBuilder对象
     */
    public StringBuilder() {
        super(16);
    }

    /**
     * 构造一个不带任何字符的 StringBuilder 对象,其初始容量由 capacity 参数指定
     * @param  capacity 初始容量
     * @return          StringBuilder对象
     */
    public StringBuilder(int capacity) {
        super(capacity);
    }

    /**
     * 构造一个 StringBuilder 对象,并初始化为指定的字符串内容,初始容量为 str.length() + 16
     * @param  str 指定的字符串内容
     * @return     StringBuilder对象
     */
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

    /**
     * 构造一个 StringBuilder 对象,包含与指定的 CharSequence 相同的字符,初始容量为 seq.length() + 16
     * @param  seq CharSequence字符
     * @return     StringBuilder对象
     */
    public StringBuilder(CharSequence seq) {
        this(seq.length() + 16);
        append(seq);
    }

}

成员方法

类型方法说明
StringBuilderappend(T t)添加各种类型的数据
StringBuilderinsert(int offset, T t)在容器指定位置插入各种类型的数据
StringBuilderdeleteCharAt(int index)删除指定位置的字符
StringBuilderdelete(int start, int end)移除此序列的子字符串中的字符
StringBuilderreplace(int start, int end, String str)替换
charcharAt(int index)获取指定索引处的 char 值
intlength()元素个数
intcapacity()当前容量
intindexOf(String str)返回第一次出现的指定子字符串在该字符串的索引
intlastIndexOf(String str)返回最右边出现的指定子字符串在此字符串的索引
Stringsubstring(int start)截取
Stringsubstring(int start, int end)返回包含此字符序列当前所包含的字符子序列
StringBuilderreverse()反转
StringtoString()返回此序列中数据的字符串表示形式

标题:Java基础—String
作者:Hefery
地址:http://hefery.icu/articles/2022/03/29/1648490516730.html