Java String 源代码分析

String类的字段主要有下面几个:
final char value[], 字符数组主要用于存放字符
final int offset,字符数组的第一个元素下标
final int count,字符数组中元素的数量统计
int hash,字符串的hash值
构造函数

如果我们平时这样定义数组,那么会得到一个空的字符数组,并且是不可变的。
String str = new String();

public String() {
        this.offset = 0;
        this.count = 0;
        this.value = new char[0];
    }

下一种使用字符串来初始化对象:
String str = new String(“abc”);
这里代码中处理了如果初始化的字符串两边有垃圾字符,或者是空格等的情况,会删除掉这些字符。

public String(String original) {
        int size = original.count;
        char[] originalValue = original.value;
        char[] v;
        if (originalValue.length > size) {
            // The array representing the String is bigger than the new
            // String itself.  Perhaps this constructor is being called
            // in order to trim the baggage, so make a copy of the array.
            int off = original.offset;
            v = Arrays.copyOfRange(originalValue, off, off+size);
        } else {
            // The array representing the String is the same
            // size as the String, so no point in making a copy.
            v = originalValue;
        }
        this.offset = 0;
        this.count = size;
        this.value = v;
    }

使用字符数组构造字符串
String str = new String(new char[]{‘a’,’b’});

public String(char value[]) {
        int size = value.length;
        this.offset = 0;
        this.count = size;
        this.value = Arrays.copyOf(value, size);
    }

其他还有很多灵活的构造函数,但是大多使用了Arrays的方法。

常用方法

  1. 返回字符串长度
public int length() {
        return count;
    }
  1. 判断字符串是否为空
public boolean isEmpty() {
        return count == 0;
    }
  1. 根据下标查找元素:
public char charAt(int index) {
        if ((index < 0) || (index >= count)) {
            throw new StringIndexOutOfBoundsException(index);
        }
        return value[index + offset];
    }
  1. 判断字符串相等
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = count;
            if (n == anotherString.count) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = offset;
                int j = anotherString.offset;
                while (n-- != 0) {
                    if (v1[i++] != v2[j++])
                        return false;
                }
                return true;
            }
        }
        return false;
    }

从这里可以看出,字符串相等的比较,是先检查字符串的长度是否相同,如果相同,则每一个字符元素进行比较,如果有其中一个不一样,则返回false。

  1. 字符串比较
 public int compareTo(String anotherString) {
        int len1 = count;
        int len2 = anotherString.count;
        int n = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;

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

这个方法就比较玄妙了,首先将参数字符串的相关字段全部都复制一份出来,然后判断两个字符数组第一个元素下标是否相同。
如果相同:从下标开始到较小长度字符串进行循环,每个字符进行比较,如果遇到字符不相等的情况,则做减法。
如果不同,也是从按照较小长度字符串的数据进行循环,每个字符进行比较做减法。

  1. startsWith(String prefix)
 public boolean startsWith(String prefix) {
        return startsWith(prefix, 0);
 }
 public boolean startsWith(String prefix, int toffset) {
        char ta[] = value;
        int to = offset + toffset;
        char pa[] = prefix.value;
        int po = prefix.offset;
        int pc = prefix.count;
        // Note: toffset might be near -1>>>1.
        if ((toffset < 0) || (toffset > count - pc)) {
            return false;
        }
        while (--pc >= 0) {
            if (ta[to++] != pa[po++]) {
                return false;
            }
        }
        return true;
    }

这里调用了另外一个startsWith方法,传入了从第几个元素下标开始比较。默认都是0.
这里做的也是遍历传入字符串的每一个元素,判断是否相同。

  1. hashcode()
public int hashCode() {
        int h = hash;
        if (h == 0 && count > 0) {
            int off = offset;
            char val[] = value;
            int len = count;

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

计算hashcode的方法使用了这个公式。
h = 31*h+val[off++]
hashcode的要求是,同一个字符串不论这个方法调用多少次,这个值总是不变的。而且不能和其他字符串计算出来的值一样。这样会造成冲突。就是说纯粹是为了确保唯一性。
这里使用31的原因是,31在CPU上做乘法时,采用左移计算性能更高。来自网络资料。

  1. intern()
    这个方法应该算是String类里面唯一一个不是用Java实现的了。其源代码如下:
    public native String intern();
    说明是个本地方法,用C++来实现的。这个方法的作用是什么呢?
    先要说下字符串定义的方式:
    String str = “abc”;
    这种方式也可以定义字符串,不过定义的字符串全部都在常量池中有储存,如果一个String类型的对象调用了intern方法的话,那么会检查这个字符串是否在常量池中有相等的String,如果有则返回常量池的对象,如果没有,则在常量池中定义一个。这样做的办法是性能会好很多,String不在堆上。
    看一个例子:
package com.lenovo;
public class StringTest {
    public static void main(String[] args) {
        String a = "abc";
        String b = new String("abc");
        System.out.println(a==b);
        System.out.println(a==b.intern());
        System.out.println(a.equals(b));
    }
}

这个输出是:
false
true
true
显然,a,b不是同一个,但是b调用了intern方法后,就是和a同一个对象了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值