简单String源码分析

由于水平问题只能对String能够理解的部分进行简单说明。

一、String的类声明

String的类声明部分的代码:

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

String类加了final声明,也就意味着String不能被继承,其将类声明为final的主要作用是:

  1. 由于String类不能被继承,所以就不会没修改,这就避免了因为继承引起的安全隐患,因为java很多方法都是“本地方法调用”,如果重写了这些方法就可能对系统进行恶意攻击。
  2. String类在程序中出现的频率比较高,如果为了避免安全隐患,在它每次出现时都用final来修饰,这无疑会降低程序的执行效率,所以干脆直接将其设为final以提高效率(在使用final修饰方法的时候,编译器会将被final修饰过的方法插入到调用者代码处,提高运行速度和效率)。

String类实现了Serializable使得String可以进行序列化

String类实现了Comparable接口,Comparable接口主要有一个compareTo()方法,这个方法主要用于两个实例之间的比较,方便与String在集合中进行排序。

String实现了CharSequence,代表String是一个可读的字符序列,String, StringBuilder和StringBuffer本质上都是通过字符数组实现的,他们都实现了CharSequence接口,为外部提供了对于他们的内部字符数组的统一读取方法。

二、String成员变量

String成员变量有三个:

/** 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;
    
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];

其中比较重要的是value[],它的作用就是用来保存String的值。它是由final修饰,也就是说不能修改value指向的char数组,但是能够修改value[]数组保存的值。但是String并没有对外提供修改value的方法,并且String 类使用final声明,也就是说我们无法修改value的值。这也就确保了String一经创建他的值就无法修改。

serialVersionUID和serialPersistentFields是序列化时使用的

三、String方法

string的方法有很多,其方法大部分都是对于value进行操作,这里挑几个方法来看一下

1.hashCode方法
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;
    }

String的hashCode是由value的值来决定的,String的值相同他们的hashCode也相同。这里使用31作为乘积有一下原因:

a.31是质子数中一个“不大不小”的存在,如果你使用的是一个如2的较小质数,那么得出的乘积会在一个很小的范围,很容易造成哈希值的冲突。而如果选择一个100以上的质数,得出的哈希值会超出int的最大范围,这两种都不合适。而如果对超过 50,000 个英文单词(由两个不同版本的 Unix 字典合并而成)进行 hash code 运算,并使用常数 31, 33, 37, 39 和 41 作为乘子,每个常数算出的哈希值冲突数都小于7个(国外大神做的测试),那么这几个数就被作为生成hashCode值得备选乘数了。

b.JVM里最有效的计算方式就是进行位运算了:

  • 左移 << : 左边的最高位丢弃,右边补全0(把 << 左边的数据*2的移动次幂)。

  • 右移 >> : 把>>左边的数据/2的移动次幂。

  • 无符号右移 >>> : 无论最高位是0还是1,左边补齐0。

    所以 : 31 * i = (i << 5) - i(左边 312=62,右边 22^5-2=62) - 两边相等,JVM就可以高效的进行计算

2.实现了Comparable的conpareTo方法

方法实现比较简单,逐个比较字符数组中的值然后返回结果。

   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;
    }
3.intern方法

intern方法的作用是返回字符串对象的规范化表示形式,当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。,native关键字标注的方法就表示是本地调用方法,方法体里面没有显示实现,它是不是由java实现的。

public native String intern();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值