String类源码笔记(一):成员变量和构造器

String类表示字符串,所有类似"abc"形式的字符串(或魔法字符串)都被看作是这个类的实例。String是不可变的,当一个字符串在常量池中被创建时,他的值就不会被改变。

不可变类指的是其实例不能被修改的类。每个实例中包含的所有信息都必须在创建该实例的时候就提供,并且在对象的整个生命周期内固定不变。为了使类不可变,要遵循下面五条规则:
1. 不要提供任何会修改对象状态的方法
2. 保证类不会被扩展。 一般的做法是让这个类称为 final 的,防止子类化,破坏该类的不可变行为。
3. 使所有的域都是 final 的
4. 使所有的域都成为私有的。 防止客户端获得访问被域引用的可变对象的权限,并防止客户端直接修改这些对象。
5. 确保对于任何可变性组件的互斥访问。 如果类具有指向可变对象的域,则必须确保该类的客户端无法获得指向这些对象的引用。

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

所在路径:\java\lang\String.java

String类的成员变量
String类的构造器

一、成员变量

为了保证String类是一个不可变类,String类的成员变量多为私有和不可变的。

/** 存储String对象的值 */ 
private final char value[]; 
/** hashcode */ 
private int hash; 
/** serialVersionUID */ 
private static final long serialVersionUID = -6849794470754667710L;
 /** 序列化时使用,表明需要序列化的部分 */ 
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];

其中serialPersistentFields在序列化时使用:

For class that implements Serializable interface there are 2 ways to define what specific fields get streamed during the serialization:
1、By default all non-static, non-transient fields that implement Serializable are preserved.
2、By definning ObjectStreamField [] serialPersistentFields and explicitly declaring the specific fields saved.
The 'advantage' is that it does what it says in the Javadoc: defines which fields are serialized. Without it, all non-transient non-static fields are serialized. Your choice.

二、构造器

JDK8的String类一共有16个构造器,其中两个是@Deprecated,一个是私有构造器,剩下的13个是可以调用的。

1、无参构造器

无参构造器直接将""的value赋值给当前类的value。""的value是一个空的char[],其length为0。调用使用了无参构造器的String对象的isEmpty()方法会得到true,调用length()方法会得到0,判断其==null会得到false。

public String() { 
    this.value = "".value; 
}
2、入参为String对象

入参为String对象时,构造器会对其进行直接取值。

public String(String original) { 
    this.value = original.value; 
    this.hash = original.hash; 
}
3、入参为char[]

入参为字符串数组时,构造器调用的是Arrays.copyOf()方法。

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

其中Arrays.copyOf()方法是为了将入参的字符串序列深拷贝到this.valuie中,他的源码为:

public static char[] copyOf(char[] original, int newLength) {
    char[] copy = new char[newLength];
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

其中System.arraycopy()方法的源码为:

public static native void arraycopy(Object src,  int  srcPos,
                                    Object dest, int destPos,
                                    int length);

String和char[]的相互转换:
https://www.cnblogs.com/rrttp/p/7922202.html

4、入参为char[],偏移量和有效长度

这个方法支持直接传入想要生成的String的母串,通过偏移量和有效长度找出需要赋值给this.value的部分,然后调用Arrays.copyOfRange()方法进行深拷贝。

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);
}
5、其他

当需要将一个Unicode编码序列转换为String时,可以使用以下构造器:

public String(int[] codePoints, int offset, int count)

参考:https://blog.csdn.net/qq_39477410/article/details/82469104

当需要将一个bytes[]转换为String时,可以使用以下构造器:

// 可以传入JDK支持的字符集名称
public String(byte bytes[], int offset, int length, String charsetName)
    throws UnsupportedEncodingException

// 也可以传入自定义的解码字符集
public String(byte bytes[], int offset, int length, Charset charset)

此外,还有一些将上述构造器进一步封装的构造器,其本质都是简化入参。另外,String类的构造器同样支持传入StringBuffer和StringBuilder。如果传入的是StringBuffer,构造器会为其加锁。如果传入的是StringBuilder则不会加锁。

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

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

事实上,StringBuffer和StringBuilder的toString()方法调用的也是String类的构造器,他们最终的底层实现都是Arrays.copyOf()。

// StringBuffer的toString()方法
@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

// StringBuilder的toString()方法
@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

最后,String类还提供了一个保护类型的构造方法。该方法相比入参为char[]的构造器多了一个share参数,这个参数并没有实际作用,只是用来和其他构造器进行区分。当String类内部调用该构造器时:

  • 直接赋值而不是使用Arrays.copyOf()方法可以获得更高的效率;
  • 同时共享字符串数组的方式也可以节省内存。

该构造器不能对外暴露的原因是需要保持String类的不可变性。

/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
    // assert share : "unshared not supported";
    this.value = value;
}

你可能感兴趣的:(String类源码笔记(一):成员变量和构造器)