JDK1.8的String源码学习

学习String源码


标记一下
JVM我不是很了解,关于字符串常量池和value的实际位置等学完JVM回来填坑

包和引用

package java.lang;

import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Formatter;
import java.util.Locale;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

String类代表字符串。 Java程序中的所有字符串文字(例如"abc" )都被实现为此类的实例。
字符串不变; 它们的值在创建后不能被更改。 字符串缓冲区支持可变字符串。 因为String对象是不可变的,它们可以被共享。 例如:

 String str = "abc";

相当于:

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

以下是一些如何使用字符串的示例:

 System.out.println("abc");
 String cde = "cde";
 System.out.println("abc" + cde);
 String c = "abc".substring(2,3);
 String d = cde.substring(1, 2);

String类包括用于检查序列的各个字符的方法,用于比较字符串,搜索字符串,提取子字符串以及创建将所有字符翻译为大写或小写的字符串的副本。 案例映射基于Character类指定的Unicode标准版本。

Java语言为字符串连接运算符(+)提供特殊支持,并为其他对象转换为字符串。 字符串连接是通过StringBuilder (或StringBuffer )类及其append方法实现的。 字符串转换是通过方法来实现toString ,由下式定义Object和继承由在Java中的所有类。 有关字符串连接和转换的其他信息,请参阅Gosling,Joy和Steele, Java语言规范 。

除非另有说明,否则传递null参数到此类中的构造函数或方法将导致抛出NullPointerException 。

A String表示UTF-16格式的字符串,其中补充字符由代理对表示 (有关详细信息,请参阅Character课程中的Character部分)。 索引值是指char代码单元,所以补充字符在String中使用两个String 。

String类提供处理Unicode代码点(即字符)的方法,以及用于处理Unicode代码单元(即char值)的方法。

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

Serializable序列化接口
作为一个标识使JVM对此类进行序列化 具体描述参考谈谈实现Serializable接口的作用和必要性

概况: 在程序中为了能直接以 Java 对象的形式进行保存,然后再重新得到该 Java
对象,这就需要序列化能力。序列化其实可以看成是一种机制,按照一定的格式将 Java
对象的某状态转成介质可接受的形式,以方便存储或传输。其实想想就大致清楚基本流程,序列化时将 Java
对象相关的类信息、属性及属性值等等保存起来,反序列化时再根据这些信息构建出 Java
对象。而过程可能涉及到其他对象的引用,所以这里引用的对象的相关信息也要参与序列化。

Java 中进行序列化操作需要实现 Serializable 或 Externalizable 接口。

序列化作用: 提供一种简单又可扩展的对象保存恢复机制。 对于远程调用,能方便对对象进行编码和解码,就像实现对象直接传输。
可以将对象持久化到介质中,就像实现对象直接存储。 允许对象自定义外部存储的格式。

作者:selfimpr一Y 链接:https://www.jianshu.com/p/4935a87976e5

Comparable接口 主要作用是String对象之间的比较
该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法 。

  • Compares this object with the specified object for order. Returns a
    * negative integer, zero, or a positive integer as this object is less
    * than, equal to, or greater than the specified object.
    *

CharSequence接口 主要作用是为许多不同类型的字符序列(如String,StringBuffer和StringBuilder等)提供统一的只读访问(如获取长度的length方法,获取指定位置的字符charAt方法等)。

public interface CharSequenceCharSequence是char值的可读序列。 该界面提供统一的,只读访问许多不同类型的char序列。 char值代表基本多语言平面(BMP)或代理中的一个字符。 详见Unicode Character Representation 。
此界面不会完善equals和hashCode方法的一般合同。 因此,比较两个对象实现CharSequence其结果是,在一般情况下,不确定的。 每个对象可以由不同的类实现,并且不能保证每个类都能够测试其实例以与另一个类相同。 因此,使用任意的CharSequence实例作为集合中的元素或映射中的键是不合适的。

内部变量


  /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;

    /**
     * Class String is special cased within the Serialization Stream Protocol.
     *
     * A String instance is written into an ObjectOutputStream according to
     * <a href="{@docRoot}/../platform/serialization/spec/output.html">
     * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
     */
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];

private final char value[];存储字符串内容,
String string = “Hello World”;中的 “Hello World”;就是以char类型数组的形式存放在value[]中


private int hash;对应的String的hash值,默认是0 。hash是String实例化的hashcode的一个缓存。因为String经常被用于比较,比如在HashMap中。如果每次进行比较都重新计算hashcode的值的话,那无疑是比较麻烦的,而保存一个hashcode的缓存无疑能优化这样的操作。


public native String intern();
native暗示这些方法是有实现体的,只不过这些实现体是非java的

标识符native可以与所有其它的java标识符连用,但是abstract除外。这是合理的,因为native暗示这些方法是有实现体的,只不过这些实现体是非java的,但是abstract却显然的指明这些方法无实现体。native与其它java标识符连用时,其意义同非Native Method并无差别,比如native static表明这个方法可以在不产生类的实例时直接调用,这非常方便,比如当你想用一个native method去调用一个C的类库时。上面的第三个方法用到了native synchronized,JVM在进入这个方法的实现体之前会执行同步锁机制(就像java的多线程。)
一个native method方法可以返回任何java类型,包括非基本类型,而且同样可以进行异常控制。这些方法的实现体可以制一个异常并且将其抛出,这一点与java的方法非常相似。当一个native method接收到一些非基本类型时如Object或一个整型数组时,这个方法可以访问这些非基本型的内部,但是这将使这个native方法依赖于你所访问的java类的实现。有一点要牢牢记住:我们可以在一个native method的本地实现中访问所有的java特性,但是这要依赖于你所访问的java特性的实现,而且这样做远远不如在java语言中使用那些特性方便和容易。
native method的存在并不会对其他类调用这些本地方法产生任何影响,实际上调用这些方法的其他类甚至不知道它所调用的是一个本地方法。JVM将控制调用本地方法的所有细节。需要注意当我们将一个本地方法声明为final的情况。用java实现的方法体在被编译时可能会因为内联而产生效率上的提升。但是一个native final方法是否也能获得这样的好处却是值得怀疑的,但是这只是一个代码优化方面的问题,对功能实现没有影响。
如果一个含有本地方法的类被继承,子类会继承这个本地方法并且可以用java语言重写这个方法(这个似乎看起来有些奇怪),同样的如果一个本地方法被final标识,它被继承后不能被重写。
本地方法非常有用,因为它有效地扩充了JVM。事实上,我们所写的Java代码已经用到了本地方法,在Sun的Java的并发(多线程)的机制实现中,许多与操作系统的接触点都用到了本地方法,这使得java程序能够超越Java运行时的界限。有了本地方法,Java程序可以做任何应用层次的任务。

构造方法

  public String() {
        this.value = "".value;
    }
  public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }

  public String(StringBuilder builder) {
        this.value = Arrays.copyOf(builder.getValue(), builder.length());
    }
     public String(StringBuffer buffer) {
        synchronized(buffer) {
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
        }
    }

关于String,StringBuffer与StringBuilder的区别
转载自StringBuffer与StringBuilder的区别

  • String 字符串常量
  • StringBuffer 字符串变量(线程安全)
  • StringBuilder 字符串变量(非线程安全)

简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比 StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做

在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(“le”) 会使字符串缓冲区包含“startle”,而 z.insert(4, “le”) 将更改字符串缓冲区,使之包含“starlet”。
在大部分情况下 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同。


常用方法

 public int length() {
        return value.length;
    }

访问char数组的length属性获取字符串的长度
其中数组的length是用arraylength指令获取的

 public boolean isEmpty() {
        return value.length == 0;
    }

是否为空在这里插入代码片

public char charAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index];
    }

取字符串中特定位置的字符

重点 equals

比较两字符串内容是否相等
是覆盖了父类Object的equals方法
instanceof 双目运算符判断一个对象是否为一个类的实例

  1. 判断是否为同一对象
  2. 判断一个对象是否为一个类的实例
  3. 统一数据格式为String
  4. 比较长度
  5. 对两个字符串的value进行逐字符比较
 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;
    }

也是进行字符串比较的方法,关键是进行两个字符串对应位置字符的相减取差值,通过结果为正负零判断字符串之间是否相等
注意比较次数为最短字符串的长度

 public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

(未完待续。。。)
挖坑等填

  public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

public int indexOf(int ch, int fromIndex) {
        final int max = value.length;
        if (fromIndex < 0) {
            fromIndex = 0;
        } else if (fromIndex >= max) {
            // Note: fromIndex might be near -1>>>1.
            return -1;
        }

        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
            // handle most cases here (ch is a BMP code point or a
            // negative value (invalid code point))
            final char[] value = this.value;
            for (int i = fromIndex; i < max; i++) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        } else {
            return indexOfSupplementary(ch, fromIndex);
        }
    }

 public int codePointAt(int index) {
        if ((index < 0) || (index >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, value.length);
    }
  public int codePointBefore(int index) {
        int i = index - 1;
        if ((i < 0) || (i >= value.length)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointBeforeImpl(value, index, 0);
    }
 public int codePointCount(int beginIndex, int endIndex) {
        if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
            throw new IndexOutOfBoundsException();
        }
        return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
    }
public int offsetByCodePoints(int index, int codePointOffset) {
        if (index < 0 || index > value.length) {
            throw new IndexOutOfBoundsException();
        }
        return Character.offsetByCodePointsImpl(value, 0, value.length,
                index, codePointOffset);
    }

 void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }
 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值