String类源码分析(超级全)

String类源码分析

String源码精读

String类的一个最大特性是不可修改性,而导致其不可修改的原因是在String内部定义了一个常量数组,因此每次对字符串的操作实际上都会另外分配分配一个新的常量数组空间;

1、String的定义

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

从上,我们可以看出几个重点:

String是一个final类,既不能被继承的类;

String类实现了java.io.Serializable接口,可以实现序列化;

String类实现了Comparable,可以用于比较大小(按顺序比较单个字符的ASCII码);

String类实现了 CharSequence 接口,表示是一个有序字符的序列,因为String的本质是一个char类型数组。

2、字段属性

//用来存字符串,字符串的本质,是一个final的char型数组 
 private final char value[];                                          
 //缓存字符串的哈希 
 private int hash;    // Default to 0                                 
 //实现序列化的标识 
 private static final long serialVersionUID = -6849794470754667710L;  

这里需要注意的重点是:

private final char value[]这是String字符串的本质,是一个字符集合,而且是final的,是不可变的

3、构造函数

 /** 01 
* 这是一个经常会使用的String的无参构造函数. 
* 默认将""空字符串的value赋值给实例对象的value,也是空字符 
* 相当于深拷贝了空字符串"" 
*/ 
public String() { 
        this.value = "".value; 
    } 
/** 02 
* 这是一个有参构造函数,参数为一个String对象 
* 将形参的value和hash赋值给实例对象作为初始化 
* 相当于深拷贝了一个形参String对象 
*/ 
    public String(String original) { 
        this.value = original.value; 
        this.hash = original.hash; 
    } 
/** 03 
* 这是一个有参构造函数,参数为一个char字符数组 
* 虽然我不知道为什么要Arrays.copyOf去拷贝,而不直接this.value = value; 
* 意义就是通过字符数组去构建一个新的String对象 
*/ 
    public String(char value[]) { 
        this.value = Arrays.copyOf(value, value.length); 
    } 
/** 04 
* 这是一个有参构造函数,参数为char字符数组,offset(起始位置,偏移量),count(个数) 
* 作用就是在char数组的基础上,从offset位置开始计数count个,构成一个新的String的字符串 
* 意义就类似于截取count个长度的字符集合构成一个新的String对象 
*/ 
    public String(char value[], int offset, int count) { 
        if (offset < 0) {        //如果起始位置小于0,抛异常 
            throw new StringIndexOutOfBoundsException(offset); 
        } 
        if (count <= 0) { 
            if (count < 0) {     //如果个数小于0,抛异常 
                throw new StringIndexOutOfBoundsException(count); 
            } 
            if (offset <= value.length) {      //在count = 0的前提下,如果offset<=len,则返回"" 
                this.value = "".value; 
                return; 
            } 
        } 
        // Note: offset or count might be near -1>>>1. 
        //如果起始位置>字符数组长度 - 个数,则无法截取到count个字符,抛异常 
        if (offset > value.length - count) {  
            throw new StringIndexOutOfBoundsException(offset + count); 
        } 
        //重点,从offset开始,截取到offset+count位置(不包括offset+count位置) 
        this.value = Arrays.copyOfRange(value, offset, offset+count);  
    } 
/** 05 
* 这是一个有参构造函数,参数为int字符数组,offset(起始位置,偏移量),count(个数) 
* 作用跟04构造函数差不多,但是传入的不是char字符数组,而是int数组。 
* 而int数组的元素则是字符对应的ASCII整数值 
* 例子:new String(new int[]{97,98,99},0,3);   output: abc 
*/ 
    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); 
        }   
//以上都是为了处理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)); 
        } 
//上面关于BMP什么的,我暂时也没看懂,猜想关于验证int数据的正确性,通过上面的测试就进入下面的算法 
        // Pass 2: Allocate and fill in char[] 
        final char[] v = new char[n]; 
        for (int i = offset, j = 0; i < end; i++, j++) {  //从offset开始,到offset + count 
            int c = codePoints[i]; 
            if (Character.isBmpCodePoint(c)) 
                v[j] = (char)c;   //将Int类型显式缩窄转换为char类型 
            else 
                Character.toSurrogates(c, v, j++); 
        } 
        this.value = v; //最后将得到的v赋值给String对象的value,完成初始化 
    } 
/****这里把被标记为过时的构造函数去掉了***/ 
/** 06 
* 这是一个有参构造函数,参数为byte数组,offset(起始位置,偏移量),长度,和字符编码格式 
* 就是传入一个byte数组,从offset开始截取length个长度,其字符编码格式为charsetName,如UTF-8 
* 例子:new String(bytes, 2, 3, "UTF-8"); 
*/ 
    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); 
    } 
/** 07 
* 类似06 
*/ 
    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); 
    } 
/** 08 
* 这是一个有参构造函数,参数为byte数组和字符集编码 
* 用charsetName的方式构建byte数组成一个String对象 
*/ 
    public String(byte bytes[], String charsetName) 
            throws UnsupportedEncodingException { 
        this(bytes, 0, bytes.length, charsetName); 
    } 
/** 09 
* 类似08 
*/ 
    public String(byte bytes[], Charset charset) { 
        this(bytes, 0, bytes.length, charset); 
    } 
/** 10 
* 这是一个有参构造函数,参数为byte数组,offset(起始位置,偏移量),length(个数) 
* 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。 
*  
*/ 
    public String(byte bytes[], int offset, int length) { 
        checkBounds(bytes, offset, length); 
        this.value = StringCoding.decode(bytes, offset, length); 
    } 
/** 11 
* 这是一个有参构造函数,参数为byte数组 
* 通过使用平台默认字符集编码解码传入的byte数组,构造成一个String对象,不需要截取 
*  
*/ 
    public String(byte bytes[]) { 
        this(bytes, 0, bytes.length); 
    } 
/** 12 
* 有参构造函数,参数为StringBuffer类型 
* 就是将StringBuffer构建成一个新的String,比较特别的就是这个方法有synchronized锁 
* 同一时间只允许一个线程对这个buffer构建成String对象 
*/ 
    public String(StringBuffer buffer) { 
        synchronized(buffer) { 
            this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); //使用拷贝的方式 
        } 
    } 
/** 13 
* 有参构造函数,参数为StringBuilder 
* 同12差不多,只不过是StringBuilder的版本,差别就是没有实现线程安全 
*/ 
    public String(StringBuilder builder) { 
        this.value = Arrays.copyOf(builder.getValue(), builder.length()); 
    } 
/** 14 
* 这个构造函数比较特殊,有用的参数只有char数组value,是一个不对外公开的构造函数,没有访问修饰符 
* 加入这个share的只是为了区分于String(char[] value)方法,用于重载,功能类似于03,我也在03表示过疑惑。 
* 为什么提供这个方法呢,因为性能好,不需要拷贝。为什么不对外提供呢?因为对外提供会打破value为不变数组的限制。 
* 如果对外提供这个方法让String与外部的value产生关联,如果修改外不的value,会影响String的value。所以不能 
* 对外提供 
*/ 
    String(char[] value, boolean share) { 
        // assert share : "unshared not supported"; 
        this.value = value; 
    } 

展示了总共14种构造方法:

  • 可以构造空字符串对象,既"";
  • 可以根据String,StringBuilder,StringBuffer构造字符串对象;
  • 可以根据char数组,其子数组构造字符串对象;
  • 可以根据int数组,其子数组构造字符串对象;
  • 可以根据某个字符集编码对byte数组,其子数组解码并构造字符串对象;

4、长度和是否为空函数

public int length() {       //所以String的长度就是一个value的长度 
        return value.length; 
    } 
public boolean isEmpty() {  //当char数组的长度为0,则代表String为"",空字符串 
  			return value.length == 0; 
} 

5、charAt、codePointAt类型函数

/** 
   * 返回String对象的char数组index位置的元素 
   */ 
   public char charAt(int index) { 
        if ((index < 0) || (index >= value.length)) {   //index不允许小于0,不允许大于等于String的长度 
            throw new StringIndexOutOfBoundsException(index); 
        } 
        return value[index]; //返回 
    } 
   /** 
    * 返回String对象的char数组index位置的元素的ASSIC码(int类型) 
    */ 
    public int codePointAt(int index) { 
        if ((index < 0) || (index >= value.length)) { 
            throw new StringIndexOutOfBoundsException(index); 
        } 
        return Character.codePointAtImpl(value, index, value.length); 
    } 
   /** 
    * 返回index位置元素的前一个元素的ASSIC码(int型) 
    */ 
    public int codePointBefore(int index) { 
        int i = index - 1;  //获得index前一个元素的索引位置 
        if ((i < 0) || (i >= value.length)) { //所以,index不能等于0,因为i = 0 - 1 = -1 
            throw new StringIndexOutOfBoundsException(index); 
        } 
        return Character.codePointBeforeImpl(value, index, 0); 
    } 
   /** 
* 方法返回的是代码点个数,是实际上的字符个数,功能类似于length() 
* 对于正常的String来说,length方法和codePointCount没有区别,都是返回字符个数。 
* 但当String是Unicode类型时则有区别了。 
* 例如:String str = “/uD835/uDD6B” (即使 'Z' ), length() = 2 ,codePointCount() = 1 
*/ 
    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); 
    } 
   /** 
* 也是相对Unicode字符集而言的,从index索引位置算起,偏移codePointOffset个位置,返回偏移后的位置是多少 
* 例如,index = 2 ,codePointOffset = 3 ,maybe返回 5  
*/ 
    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); 
    } 

6、getChar、getBytes类型函数

  /** 
* 这是一个不对外的方法,是给String内部调用的,因为它是没有访问修饰符的,只允许同一包下的类访问 
* 参数:dst[]是目标数组,dstBegin是目标数组的偏移量,既要复制过去的起始位置(从目标数组的什么位置覆盖) 
* 作用就是将String的字符数组value整个复制到dst字符数组中,在dst数组的dstBegin位置开始拷贝 
*  
*/ 
void getChars(char dst[], int dstBegin) { 
        System.arraycopy(value, 0, dst, dstBegin, value.length); 
    } 
   /** 
* 得到char字符数组,原理是getChars() 方法将一个字符串的字符复制到目标字符数组中。  
* 参数:srcBegin是原始字符串的起始位置,srcEnd是原始字符串要复制的字符末尾的后一个位置(既复制区域不包括srcEnd) 
* dst[]是目标字符数组,dstBegin是目标字符的复制偏移量,复制的字符从目标字符数组的dstBegin位置开始覆盖。 
*/ 
    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { 
        if (srcBegin < 0) {           //如果srcBegin小于,抛异常 
            throw new StringIndexOutOfBoundsException(srcBegin); 
        } 
    *    if (srcEnd > value.length) {  //如果srcEnd大于字符串的长度,抛异常 
            throw new StringIndexOutOfBoundsException(srcEnd); 
        } 
        if (srcBegin > srcEnd) {      //如果原始字符串其实位置大于末尾位置,抛异常 
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); 
        } 
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 
    } 
   /****去除被标记过时的方法****/ 
   /** 
    * 获得charsetName编码格式的bytes数组 
*/ 
    public byte[] getBytes(String charsetName) 
            throws UnsupportedEncodingException { 
        if (charsetName == null) throw new NullPointerException(); 
        return StringCoding.encode(charsetName, value, 0, value.length); 
    } 
   /** 
    * 与上个方法类似,但charsetName和charset的区别,我还没搞定,搞懂来再更新 
*/ 
    public byte[] getBytes(Charset charset) { 
        if (charset == null) throw new NullPointerException(); 
        return StringCoding.encode(charset, value, 0, value.length); 
    } 
/** 
    * 使用平台默认的编码格式获得bytes数组 
*/ 
    public byte[] getBytes() { 
        return StringCoding.encode(value, 0, value.length); 
    } 

7、equal类函数(是否相等)

/** 
* String的equals方法,重写了Object的equals方法(区分大小写) 
* 比较的是两个字符串的值是否相等 
* 参数是一个Object对象,而不是一个String对象。这是因为重写的是Object的equals方法,所以是Object 
* 如果是String自己独有的方法,则可以传入String对象,不用多此一举 
*  
* 实例:str1.equals(str2) 
*/ 
public boolean equals(Object anObject) { 
        if (this == anObject) {   //首先判断形参str2是否跟当前对象str1是同一个对象,既比较地址是否相等 
            return true;          //如果地址相等,那么自然值也相等,毕竟是同一个字符串对象 
        } 
        if (anObject instanceof String) {  //判断str2对象是否是一个String类型,过滤掉非String类型的比较 
            String anotherString = (String)anObject; //如果是String类型,转换为String类型 
            int n = value.length;                    //获得当前对象str1的长度 
            if (n == anotherString.value.length) {   //比较str1的长度和str2的长度是否相等 
                                                     //如是进入核心算法 
                char v1[] = value;                   //v1为当前对象str1的值,v2为参数对象str2的值 
                char v2[] = anotherString.value; 
                int i = 0;                           //就类似于for的int i =0的作用,因为这里使用while 
                while (n-- != 0) {                   //每次循环长度-1,直到长度消耗完,循环结束  
                    if (v1[i] != v2[i])              //同索引位置的字符元素逐一比较 
                        return false;                //只要有一个不相等,则返回false 
                    i++; 
                } 
                return true;                         //如比较期间没有问题,则说明相等,返回true 
            } 
        } 
        return false; 
    } 

8、regionMatchs()方法

/** 
* 这是一个类似于equals的方法,比较的是字符串的片段,也即是部分区域的比较 
* toffset是当前字符串的比较起始位置(偏移量),other是要比较的String对象参数,ooffset是要参数String的比较片段起始位置,len是两个字符串要比较的片段的长度大小 
*/ 
public boolean regionMatches(int toffset, String other, int ooffset, 
            int len) { 
        char ta[] = value;  //当前对象的值 
        int to = toffset;   //当前对象的比较片段的起始位置,既偏移量 
        char pa[] = other.value;  //参数,既比较字符串的值 
        int po = ooffset;         //比较字符串的起始位置 
        // Note: toffset, ooffset, or len might be near -1>>>1. 
        if ((ooffset < 0) || (toffset < 0)  //起始位置不小于0或起始位置不大于字符串长度 - 片段长度,大于就截取不到这么长的片段了 
                || (toffset > (long)value.length - len) 
                || (ooffset > (long)other.value.length - len)) { 
            return false;      //惊讶脸,居然不是抛异常,而是返回false 
        } 
        while (len-- > 0) {               //使用while循环,当然也可以使for循环 
            if (ta[to++] != pa[po++]) {   //片段区域的字符元素逐个比较 
                return false; 
            } 
        } 
        return true; 
    } 


/** 
* 这个跟上面的方法一样,只不过多了一个参数,既ignoreCase,既是否为区分大小写。 
* 是equalsIgnoreCase()方法的片段比较版本,实际上equalsIgnoreCase()也是调用regionMatches函数 
*/ 
    public boolean regionMatches(boolean ignoreCase, int toffset, 
            String other, int ooffset, int len) { 
        char ta[] = value; 
        int to = toffset; 
        char pa[] = other.value; 
        int po = ooffset; 
        // Note: toffset, ooffset, or len might be near -1>>>1. 
        if ((ooffset < 0) || (toffset < 0) 
                || (toffset > (long)value.length - len) 
                || (ooffset > (long)other.value.length - len)) { 
            return false; 
        } 
//上面的解释同上 
        while (len-- > 0) { 
            char c1 = ta[to++]; 
            char c2 = pa[po++]; 
            if (c1 == c2) { 
                continue; 
            } 
            if (ignoreCase) {   //当ignoreCase为true时,既忽视大小写时 
                // If characters don't match but case may be ignored, 
                // try converting both characters to uppercase. 
                // If the results match, then the comparison scan should 
                // continue. 
                char u1 = Character.toUpperCase(c1);   //片段中每个字符转换为大写 
                char u2 = Character.toUpperCase(c2); 
                if (u1 == u2) { //大写比较一次,如果相等则不执行下面的语句,进入下一个循环 
                    continue; 
                } 
                // Unfortunately, conversion to uppercase does not work properly 
                // for the Georgian alphabet, which has strange rules about case 
                // conversion.  So we need to make one last check before 
                // exiting. 
                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { 
                 //每个字符换行成小写比较一次 
                    continue; 
                } 
            } 
            return false; 
        } 
        return true; 
    } 

  • 片段比较时针对String对象的;所以如果你要跟StringBuffer和StringBuilder比较,那么记得toString;
  • 如果你要进行两个字符串之间的片段比较的话,就可以使用regionMatches,如果是完整的比较那么就equals;

9、compareTo类函数和CaseInsensitiveComparator静态内部类

/** 
* 这是一个比较字符串中字符大小的函数,因为String实现了Comparable<String>接口,所以重写了compareTo方法 
* Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。 
* 实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。 
*  
* 参数是需要比较的另一个String对象 
* 返回的int类型,正数为大,负数为小,是基于字符的ASSIC码比较的 
*  
*/ 
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;                                //相当于for的int k = 0,就是为while循环的数组服务的 
        while (k < lim) {                         //当当前索引小于两个字符串中较短字符串的长度时,循环继续 
            char c1 = v1[k];          //获得当前对象的字符 
            char c2 = v2[k];          //获得比较对象的字符 
            if (c1 != c2) {           //从前向后遍历,只要其实一个不相等,返回字符ASSIC的差值,int类型 
                return c1 - c2; 
            } 
            k++; 
        } 
        return len1 - len2;           //如果两个字符串同样位置的索引都相等,返回长度差值,完全相等则为0 
    } 
/** 
*  这时一个类似compareTo功能的方法,但是不是comparable接口的方法,是String本身的方法 
*  使用途径,我目前只知道可以用来不区分大小写的比较大小,但是不知道如何让它被工具类Collections和Arrays运用 
* 
*/ 
public int compareToIgnoreCase(String str) { 
        return CASE_INSENSITIVE_ORDER.compare(this, str); 
    } 
    /** 
    * 这是一个饿汉单例模式,是String类型的一个不区分大小写的比较器 
    * 提供给Collections和Arrays的sort方法使用 
    * 例如:Arrays.sort(strs,String.CASE_INSENSITIVE_ORDER); 
    * 效果就是会将strs字符串数组中的字符串对象进行忽视大小写的排序 
    * 
    */ 
    public static final Comparator<String> CASE_INSENSITIVE_ORDER 
                                         = new CaseInsensitiveComparator(); 
/** 
* 这一个私有的静态内部类,只允许String类本身调用 
* 实现了序列化接口和比较器接口,comparable接口和comparator是有区别的 
* 重写了compare方法,该静态内部类实际就是一个String类的比较器 
* 
*/ 
private static class CaseInsensitiveComparator 
            implements Comparator<String>, java.io.Serializable { 
        // use serialVersionUID from JDK 1.2.2 for interoperability 
        private static final long serialVersionUID = 8575799808933029326L; 
        public int compare(String s1, String s2) { 
            int n1 = s1.length();                 //s1字符串的长度 
            int n2 = s2.length();                 //s2字符串的长度 
            int min = Math.min(n1, n2);           //获得最小长度  
            for (int i = 0; i < min; i++) { 
                char c1 = s1.charAt(i);           //逐一获得字符串i位置的字符 
                char c2 = s2.charAt(i); 
                if (c1 != c2) {                   //部分大小写比较一次 
                    c1 = Character.toUpperCase(c1);    //转换大写比较一次 
                    c2 = Character.toUpperCase(c2); 
                    if (c1 != c2) { 
                        c1 = Character.toLowerCase(c1);  //转换小写比较一次 
                        c2 = Character.toLowerCase(c2); 
                        if (c1 != c2) {                  //返回字符差值 
                            // No overflow because of numeric promotion 
                            return c1 - c2; 
                        } 
                    } 
                } 
            } 
            return n1 - n2;  //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数 
        } 
        /** Replaces the de-serialized object. */ 
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; } 
    } 

10、startWith、endWith类函数

/** 
* 作用就是当前对象[toffset,toffset + prefix.value.lenght]区间的字符串片段等于prefix 
* 也可以说当前对象的toffset位置开始是否以prefix作为前缀 
* prefix是需要判断的前缀字符串,toffset是当前对象的判断起始位置 
*/ 
    public boolean startsWith(String prefix, int toffset) { 
        char ta[] = value;     //获得当前对象的值 
        int to = toffset;      //获得需要判断的起始位置,偏移量 
        char pa[] = prefix.value; //获得前缀字符串的值 
        int po = 0; 
        int pc = prefix.value.length; 
        // Note: toffset might be near -1>>>1. 
        if ((toffset < 0) || (toffset > value.length - pc)) {  //偏移量不能小于0且能截取pc个长度 
                    return false;  //不能则返回false 
        } 
        while (--pc >= 0) {                  //循环pc次,既prefix的长度 
            if (ta[to++] != pa[po++]) {      //每次比较当前对象的字符串的字符是否跟prefix一样 
                return false;                //一样则pc--,to++,po++,有一个不同则返回false 
            } 
        } 
        return true;  //没有不一样则返回true,当前对象是以prefix在toffset位置做为开头 
    } 
/** 
* 判断当前字符串对象是否以字符串prefix起头 
* 是返回true,否返回fasle 
*/ 
    public boolean startsWith(String prefix) { 
        return startsWith(prefix, 0); 
    } 
/** 
* 判断当前字符串对象是否以字符串prefix结尾 
* 是返回true,否返回fasle 
*/ 
    public boolean endsWith(String suffix) { 
    //suffix是需要判断是否为尾部的字符串。 
    //value.length - suffix.value.length是suffix在当前对象的起始位置 
        return startsWith(suffix, value.length - suffix.value.length);  
    } 

11、hashCode()函数

/** 
   * 这是String字符串重写了Object类的hashCode方法。 
   * 给由哈希表来实现的数据结构来使用,比如String对象要放入HashMap中。 
   * 如果没有重写HashCode,或HaseCode质量很差则会导致严重的后果,既不靠谱的后果 
   * 
   */ 
   public int hashCode() { 
        int h = hash;  //hash是属性字段,是成员变量,所以默认为0 
        if (h == 0 && value.length > 0) { //如果hash为0,且字符串对象长度大于0,不为"" 
            char val[] = value;   //获得当前对象的值 
//重点,String的哈希函数 
            for (int i = 0; i < value.length; i++) {  //遍历len次 
                h = 31 * h + val[i];         //每次都是31 * 每次循环获得的h +第i个字符的ASSIC码 
            } 
            hash = h; 
        } 
        return h;  //由此可见""空字符对象的哈希值为0 
    } 

12、indexOf、lastIndexOf类函数

/** 
* 返回cn对应的字符在字符串中第一次出现的位置,从字符串的索引0位置开始遍历 
*  
*/ 
    public int indexOf(int ch) { 
        return indexOf(ch, 0); 
    } 
/** 
 * index方法就是返回ch字符第一次在字符串中出现的位置 
 * 既从fromIndex位置开始查找,从头向尾遍历,ch整数对应的字符在字符串中第一次出现的位置 
 * -1代表字符串没有这个字符,整数代表字符第一次出现在字符串的位置 
 */ 
    public int indexOf(int ch, int fromIndex) { 
        final int max = value.length; //获得字符串对象的长度 
        if (fromIndex < 0) {             //如果偏移量小于0,则代表偏移量为0,校正偏移量 
            fromIndex = 0; 
        } else if (fromIndex >= max) {   //如果偏移量大于最大长度,则返回-1,代表没有字符串没有ch对应的字符 
            // Note: fromIndex might be near -1>>>1. 
            return -1; 
        } 
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { //emmm,这个判断,不懂 
            // 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++) {      //从fromIndex位置开始向后遍历 
                if (value[i] == ch) {                    //只有字符串中的某个位置的元素等于ch 
                    return i;                            //返回对应的位置,函数结束,既第一次出现的位置 
                } 
            } 
            return -1;  //如果没有出现,则返回-1 
        } else { 
            return indexOfSupplementary(ch, fromIndex);  //emmm,紧紧接着没看懂的地方 
        } 
    } 
    private int indexOfSupplementary(int ch, int fromIndex) { 
        if (Character.isValidCodePoint(ch)) { 
            final char[] value = this.value; 
            final char hi = Character.highSurrogate(ch); 
            final char lo = Character.lowSurrogate(ch); 
            final int max = value.length - 1; 
            for (int i = fromIndex; i < max; i++) { 
                if (value[i] == hi && value[i + 1] == lo) { 
                    return i; 
                } 
            } 
        } 
        return -1; 
    } 
/** 
* 从尾部向头部遍历,返回cn第一次出现的位置,value.length - 1就是起点  
* 为了理解,我们可以认为是返回cn对应的字符在字符串中最后出现的位置 
*   
* ch是字符对应的整数 
*/ 
    public int lastIndexOf(int ch) { 
        return lastIndexOf(ch, value.length - 1); 
    } 
/** 
* 从尾部向头部遍历,从fromIndex开始作为起点,返回ch对应字符第一次在字符串出现的位置 
* 既从头向尾遍历,返回cn对应字符在字符串中最后出现的一次位置,fromIndex为结束点 
* 
*/ 
    public int lastIndexOf(int ch, int fromIndex) { 
        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {  //之后不解释了,emmmmmmm 
            // handle most cases here (ch is a BMP code point or a 
            // negative value (invalid code point)) 
            final char[] value = this.value; 
            //取最小值,作用就是校正,如果fromIndex传大了,就当时len - 1 
            int i = Math.min(fromIndex, value.length - 1);    
            for (; i >= 0; i--) {      //算法中是从后向前遍历,直到i<0,退出循环 
                if (value[i] == ch) {  //只有有相等,返回对应的索引位置 
                    return i; 
                } 
            } 
            return -1;   //没有找到则返回-1 
        } else { 
            return lastIndexOfSupplementary(ch, fromIndex); 
        } 
    } 
    private int lastIndexOfSupplementary(int ch, int fromIndex) { 
        if (Character.isValidCodePoint(ch)) { 
            final char[] value = this.value; 
            char hi = Character.highSurrogate(ch); 
            char lo = Character.lowSurrogate(ch); 
            int i = Math.min(fromIndex, value.length - 2); 
            for (; i >= 0; i--) { 
                if (value[i] == hi && value[i + 1] == lo) { 
                    return i; 
                } 
            } 
        } 
        return -1; 
    } 
/** 
* 返回第一次出现的字符串的位置 
* 
*/ 
    public int indexOf(String str) { 
        return indexOf(str, 0); 
    } 
/** 
* 
* 从fromIndex开始遍历,返回第一次出现str字符串的位置 
* 
*/ 
    public int indexOf(String str, int fromIndex) { 
        return indexOf(value, 0, value.length, 
                str.value, 0, str.value.length, fromIndex); 
    } 
/** 
* 这是一个不对外公开的静态函数 
* source就是原始字符串,sourceOffset就是原始字符串的偏移量,起始位置。 
* sourceCount就是原始字符串的长度,target就是要查找的字符串。 
* fromIndex就是从原始字符串的第fromIndex开始遍历 
* 
*/ 
    static int indexOf(char[] source, int sourceOffset, int sourceCount, 
            String target, int fromIndex) { 
        return indexOf(source, sourceOffset, sourceCount, 
                       target.value, 0, target.value.length, 
                       fromIndex); 
    } 
/** 
* 同是一个不对外公开的静态函数 
* 比上更为强大。 
* 多了一个targetOffset和targetCount,既代表别查找的字符串也可以被切割 
*/ 
    static int indexOf(char[] source, int sourceOffset, int sourceCount, 
            char[] target, int targetOffset, int targetCount, 
            int fromIndex) { 
        if (fromIndex >= sourceCount) {   //如果查找的起点大于当前对象的大小 
        //如果目标字符串的长度为0,则代表目标字符串为"",""在任何字符串都会出现 
        //配合fromIndex >= sourceCount,所以校正第一次出现在最尾部,仅仅是校正作用 
            return (targetCount == 0 ? sourceCount : -1);  
        } 
        if (fromIndex < 0) {  //也是校正,如果起始点小于0,则返回0 
            fromIndex = 0; 
        } 
        if (targetCount == 0) { //如果目标字符串长度为0,代表为"",则第一次出现在遍历起始点fromIndex 
            return fromIndex; 
        } 
        char first = target[targetOffset];   //目标字符串的第一个字符 
        int max = sourceOffset + (sourceCount - targetCount); //最大遍历次数 
        for (int i = sourceOffset + fromIndex; i <= max; i++) { 
            /* Look for first character. */ 
            if (source[i] != first) { 
                while (++i <= max && source[i] != first); 
            } 
            /* Found first character, now look at the rest of v2 */ 
            if (i <= max) { 
                int j = i + 1; 
                int end = j + targetCount - 1; 
                for (int k = targetOffset + 1; j < end && source[j] 
                        == target[k]; j++, k++); 
                if (j == end) { 
                    /* Found whole string. */ 
                    return i - sourceOffset; 
                } 
            } 
        } 
        return -1; 
    } 
/** 
* 查找字符串Str最后一次出现的位置 
*/ 
    public int lastIndexOf(String str) { 
        return lastIndexOf(str, value.length); 
    } 
    public int lastIndexOf(String str, int fromIndex) { 
        return lastIndexOf(value, 0, value.length, 
                str.value, 0, str.value.length, fromIndex); 
    } 
    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, 
            String target, int fromIndex) { 
        return lastIndexOf(source, sourceOffset, sourceCount, 
                       target.value, 0, target.value.length, 
                       fromIndex); 
    } 
    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount, 
            char[] target, int targetOffset, int targetCount, 
            int fromIndex) { 
        /* 
         * Check arguments; return immediately where possible. For 
         * consistency, don't check for null str. 
         */ 
        int rightIndex = sourceCount - targetCount; 
        if (fromIndex < 0) { 
            return -1; 
        } 
        if (fromIndex > rightIndex) { 
            fromIndex = rightIndex; 
        } 
        /* Empty string always matches. */ 
        if (targetCount == 0) { 
            return fromIndex; 
        } 
        int strLastIndex = targetOffset + targetCount - 1; 
        char strLastChar = target[strLastIndex]; 
        int min = sourceOffset + targetCount - 1; 
        int i = min + fromIndex; 
    startSearchForLastChar: 
        while (true) { 
            while (i >= min && source[i] != strLastChar) { 
                i--; 
            } 
            if (i < min) { 
                return -1; 
            } 
            int j = i - 1; 
            int start = j - (targetCount - 1); 
            int k = strLastIndex - 1; 
            while (j > start) { 
                if (source[j--] != target[k--]) { 
                    i--; 
                    continue startSearchForLastChar; 
                } 
            } 
            return start - sourceOffset + 1; 
        } 
    } 

只对外提供了int整形,String字符串两种参数的重载方法;

13、substring()函数

/** 
*  截取当前字符串对象的片段,组成一个新的字符串对象 
*  beginIndex为截取的初始位置,默认截到len - 1位置 
*/ 
public String substring(int beginIndex) { 
        if (beginIndex < 0) {   //小于0抛异常 
            throw new StringIndexOutOfBoundsException(beginIndex); 
        } 
        int subLen = value.length - beginIndex;  //新字符串的长度 
        if (subLen < 0) {       //小于0抛异常 
            throw new StringIndexOutOfBoundsException(subLen); 
        } 
        //如果beginIndex是0,则不用截取,返回自己(非新对象),否则截取0到subLen位置,不包括(subLen) 
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); 
    } 

/** 
* 截取一个区间范围 
* [beginIndex,endIndex),不包括endIndex 
*/ 
    public String substring(int beginIndex, int endIndex) { 
        if (beginIndex < 0) { 
            throw new StringIndexOutOfBoundsException(beginIndex); 
        } 
        if (endIndex > value.length) { 
            throw new StringIndexOutOfBoundsException(endIndex); 
        } 
        int subLen = endIndex - beginIndex; 
        if (subLen < 0) { 
            throw new StringIndexOutOfBoundsException(subLen); 
        } 
        return ((beginIndex == 0) && (endIndex == value.length)) ? this 
                : new String(value, beginIndex, subLen); 
    } 
    public CharSequence subSequence(int beginIndex, int endIndex) { 
        return this.substring(beginIndex, endIndex); 
    } 

  • substring函数是一个不完全闭包的区间,是[beginIndex,end),不包括end位置;
  • subString的原理是通过String的构造函数实现的;

14、concat()函数

/** 
* String的拼接函数 
* 例如:String  str = "abc"; str.concat("def")    output: "abcdef" 
* 
*/ 
public String concat(String str) { 
        int otherLen = str.length();//获得参数字符串的长度 
        if (otherLen == 0) { //如果长度为0,则代表不需要拼接,因为str为"" 
            return this; 
        } 
/****重点****/ 
        int len = value.length;  //获得当前对象的长度  
        //将数组扩容,将value数组拷贝到buf数组中,长度为len + str.lenght 
        char buf[] = Arrays.copyOf(value, len + otherLen);  
        str.getChars(buf, len); //然后将str字符串从buf字符数组的len位置开始覆盖,得到一个完整的buf字符数组 
        return new String(buf, true);//构建新的String对象,调用私有的String构造方法 
    } 

15、replace、replaceAll类函数

public String replace(char oldChar, char newChar) { 
        if (oldChar != newChar) {    //如果旧字符不等于新字符的情况下 
            int len = value.length;  //获得字符串长度 
            int i = -1;              //flag 
            char[] val = value; /* avoid getfield opcode */ 
            while (++i < len) {      //循环len次 
                if (val[i] == oldChar) { //找到第一个旧字符,打断循环 
                    break; 
                } 
            } 
            if (i < len) {   //如果第一个旧字符的位置小于len 
                char buf[] = new char[len];new一个字符数组,len个长度 
                for (int j = 0; j < i; j++) { 
                    buf[j] = val[j];        把旧字符的前面的字符都复制到新字符数组上 
                } 
                while (i < len) {           //从i位置开始遍历 
                    char c = val[i]; 
                    buf[i] = (c == oldChar) ? newChar : c; //发生旧字符就替换,不想关的则直接复制 
                    i++; 
                } 
                return new String(buf, true);  //通过新字符数组buf重构一个新String对象 
            } 
        } 
        return this;  //如果old = new ,直接返回自己 
    } 
//替换第一个旧字符 
String replaceFirst(String regex, String replacement) { 
        return Pattern.compile(regex).matcher(this).replaceFirst(replacement); 
    } 
//当不是正规表达式时,与replace效果一样,都是全体换。如果字符串的正则表达式,则规矩表达式全体替换 
    public String replaceAll(String regex, String replacement) { 
        return Pattern.compile(regex).matcher(this).replaceAll(replacement); 
    } 
//可以用旧字符串去替换新字符串 
    public String replace(CharSequence target, CharSequence replacement) { 
        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( 
                this).replaceAll(Matcher.quoteReplacement(replacement.toString())); 
    } 

从replace的算法中,我们可以发现,它不是从头开始遍历替换的,而是首先找到第一个要替换的字符,从要替换的字符开始遍历,发现一个替换一个;

16、matches()和contains()函数;

/** 
* matches() 方法用于检测字符串是否匹配给定的正则表达式。 
* regex -- 匹配字符串的正则表达式。 
* 如:String Str = new String("www.snailmann.com"); 
* System.out.println(Str.matches("(.*)snailmann(.*)"));   output:true 
* System.out.println(Str.matches("www(.*)"));             output:true 
*/ 
public boolean matches(String regex) { 
        return Pattern.matches(regex, this);   //实际使用的是Pattern.matches()方法 
    } 
//是否含有CharSequence这个子类元素,通常用于StrngBuffer,StringBuilder 
    public boolean contains(CharSequence s) { 
        return indexOf(s.toString()) > -1; 
    } 

17、split()函数

public String[] split(String regex, int limit) { 
        /* fastpath if the regex is a 
         (1)one-char String and this character is not one of the 
            RegEx's meta characters ".$|()[{^?*+\\", or 
         (2)two-char String and the first char is the backslash and 
            the second is not the ascii digit or ascii letter. 
         */ 
        char ch = 0; 
        if (((regex.value.length == 1 && 
             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || 
             (regex.length() == 2 && 
              regex.charAt(0) == '\\' && 
              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && 
              ((ch-'a')|('z'-ch)) < 0 && 
              ((ch-'A')|('Z'-ch)) < 0)) && 
            (ch < Character.MIN_HIGH_SURROGATE || 
             ch > Character.MAX_LOW_SURROGATE)) 
        { 
            int off = 0; 
            int next = 0; 
            boolean limited = limit > 0; 
            ArrayList<String> list = new ArrayList<>(); 
            while ((next = indexOf(ch, off)) != -1) { 
                if (!limited || list.size() < limit - 1) { 
                    list.add(substring(off, next)); 
                    off = next + 1; 
                } else {    // last one 
                    //assert (list.size() == limit - 1); 
                    list.add(substring(off, value.length)); 
                    off = value.length; 
                    break; 
                } 
            } 
            // If no match was found, return this 
            if (off == 0) 
                return new String[]{this}; 
            // Add remaining segment 
            if (!limited || list.size() < limit) 
                list.add(substring(off, value.length)); 
            // Construct result 
            int resultSize = list.size(); 
            if (limit == 0) { 
                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) { 
                    resultSize--; 
                } 
            } 
            String[] result = new String[resultSize]; 
            return list.subList(0, resultSize).toArray(result); 
        } 
        return Pattern.compile(regex).split(this, limit); 
    } 
    public String[] split(String regex) { 
        return split(regex, 0); 
    } 

18、join()函数

/** 
  * join方法是JDK1.8加入的新函数,静态方法 
  * 这个方法就是跟split有些对立的函数,不过join是静态方法 
  * delimiter就是分割符,后面就是要追加的可变参数,比如str1,str2,str3 
  *  
  * 例子:String.join(",",new String("a"),new String("b"),new String("c")) 
  * output: "a,b,c" 
  */ 
  public static String join(CharSequence delimiter, CharSequence... elements) { 
        Objects.requireNonNull(delimiter);  //就是检测是否为Null,是null,抛异常 
        Objects.requireNonNull(elements);   //不是就返回自己,即nothing happen 
        // Number of elements not likely worth Arrays.stream overhead. 
        StringJoiner joiner = new StringJoiner(delimiter);  //嗯,有兴趣自己看StringJoiner类源码啦 
        for (CharSequence cs: elements) { 
            joiner.add(cs);   //既用分割符delimiter将所有可变参数的字符串分割,合并成一个字符串 
        } 
        return joiner.toString(); 
    } 

  • Java 1.8加入的新功能,有点跟split对立的意思,是个静态方法;
  • 有两个重载方法,一个是直接传字符串数组,另个是传集合。传集合的方式是一个好功能,很方遍将集合的字符串元素拼接成一个字符串;

19、trim()函数

/** 
* 去除字符串首尾部分的空值,如,' ' or " ",非"" 
* 原理是通过substring去实现的,首尾各一个指针 
* 头指针发现空值就++,尾指针发现空值就-- 
* ' '的Int值为32,其实不仅仅是去空的作用,应该是整数值小于等于32的去除掉 
*/ 
   public String trim() { 
        int len = value.length; //代表尾指针,实际是尾指针+1的大小 
int st = 0;             //代表头指针 
        char[] val = value;    /* avoid getfield opcode */ 
//st<len,且字符的整数值小于32则代表有空值,st++ 
        while ((st < len) && (val[st] <= ' ')) {    
            st++; 
        } 
    //len - 1才是真正的尾指针,如果尾部元素的整数值<=32,则代表有空值,len-- 
        while ((st < len) && (val[len - 1] <= ' ')) { 
            len--; 
        } 
        //截取st到len的字符串(不包括len位置) 
        return ((st > 0) || (len < value.length)) ? substring(st, len) : this; 
    } 

20、toString()函数

//就是返回自己 
 public String toString() { 
        return this; 
 } 

21、toCharArray()函数

/** 
* 就是将String转换为字符数组并返回 
*/ 
 public char[] toCharArray() { 
        // Cannot use Arrays.copyOf because of class initialization order issues 
        char result[] = new char[value.length];     //定义一个要返回的空数组,长度为字符串长度 
        System.arraycopy(value, 0, result, 0, value.length); //拷贝 
        return result; //返回 
 } 

22、toLowerCase()、toUpperCase()函数

//en,好长,下次再更新吧,先用着吧 
public String toLowerCase(Locale locale) { 
        if (locale == null) { 
            throw new NullPointerException(); 
        } 
        int firstUpper; 
        final int len = value.length; 
        /* Now check if there are any characters that need to be changed. */ 
        scan: { 
            for (firstUpper = 0 ; firstUpper < len; ) { 
                char c = value[firstUpper]; 
                if ((c >= Character.MIN_HIGH_SURROGATE) 
                        && (c <= Character.MAX_HIGH_SURROGATE)) { 
                    int supplChar = codePointAt(firstUpper); 
                    if (supplChar != Character.toLowerCase(supplChar)) { 
                        break scan; 
                    } 
                    firstUpper += Character.charCount(supplChar); 
                } else { 
                    if (c != Character.toLowerCase(c)) { 
                        break scan; 
                    } 
                    firstUpper++; 
                } 
            } 
            return this; 
        } 
        char[] result = new char[len]; 
        int resultOffset = 0;  /* result may grow, so i+resultOffset 
                                * is the write location in result */ 
        /* Just copy the first few lowerCase characters. */ 
        System.arraycopy(value, 0, result, 0, firstUpper); 
        String lang = locale.getLanguage(); 
        boolean localeDependent = 
                (lang == "tr" || lang == "az" || lang == "lt"); 
        char[] lowerCharArray; 
        int lowerChar; 
        int srcChar; 
        int srcCount; 
        for (int i = firstUpper; i < len; i += srcCount) { 
            srcChar = (int)value[i]; 
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE 
                    && (char)srcChar <= Character.MAX_HIGH_SURROGATE) { 
                srcChar = codePointAt(i); 
                srcCount = Character.charCount(srcChar); 
            } else { 
                srcCount = 1; 
            } 
            if (localeDependent || 
                srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA 
                srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE 
                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale); 
            } else { 
                lowerChar = Character.toLowerCase(srcChar); 
            } 
            if ((lowerChar == Character.ERROR) 
                    || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { 
                if (lowerChar == Character.ERROR) { 
                    lowerCharArray = 
                            ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale); 
                } else if (srcCount == 2) { 
                    resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount; 
                    continue; 
                } else { 
                    lowerCharArray = Character.toChars(lowerChar); 
                } 
                /* Grow result if needed */ 
                int mapLen = lowerCharArray.length; 
                if (mapLen > srcCount) { 
                    char[] result2 = new char[result.length + mapLen - srcCount]; 
                    System.arraycopy(result, 0, result2, 0, i + resultOffset); 
                    result = result2; 
                } 
                for (int x = 0; x < mapLen; ++x) { 
                    result[i + resultOffset + x] = lowerCharArray[x]; 
                } 
                resultOffset += (mapLen - srcCount); 
            } else { 
                result[i + resultOffset] = (char)lowerChar; 
            } 
        } 
        return new String(result, 0, len + resultOffset); 
    } 
    public String toLowerCase() { 
        return toLowerCase(Locale.getDefault()); 
    } 
    public String toUpperCase(Locale locale) { 
        if (locale == null) { 
            throw new NullPointerException(); 
        } 
        int firstLower; 
        final int len = value.length; 
        /* Now check if there are any characters that need to be changed. */ 
        scan: { 
            for (firstLower = 0 ; firstLower < len; ) { 
                int c = (int)value[firstLower]; 
                int srcCount; 
                if ((c >= Character.MIN_HIGH_SURROGATE) 
                        && (c <= Character.MAX_HIGH_SURROGATE)) { 
                    c = codePointAt(firstLower); 
                    srcCount = Character.charCount(c); 
                } else { 
                    srcCount = 1; 
                } 
                int upperCaseChar = Character.toUpperCaseEx(c); 
                if ((upperCaseChar == Character.ERROR) 
                        || (c != upperCaseChar)) { 
                    break scan; 
                } 
                firstLower += srcCount; 
            } 
            return this; 
        } 
        /* result may grow, so i+resultOffset is the write location in result */ 
        int resultOffset = 0; 
        char[] result = new char[len]; /* may grow */ 
        /* Just copy the first few upperCase characters. */ 
        System.arraycopy(value, 0, result, 0, firstLower); 
        String lang = locale.getLanguage(); 
        boolean localeDependent = 
                (lang == "tr" || lang == "az" || lang == "lt"); 
        char[] upperCharArray; 
        int upperChar; 
        int srcChar; 
        int srcCount; 
        for (int i = firstLower; i < len; i += srcCount) { 
            srcChar = (int)value[i]; 
            if ((char)srcChar >= Character.MIN_HIGH_SURROGATE && 
                (char)srcChar <= Character.MAX_HIGH_SURROGATE) { 
                srcChar = codePointAt(i); 
                srcCount = Character.charCount(srcChar); 
            } else { 
                srcCount = 1; 
            } 
            if (localeDependent) { 
                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale); 
            } else { 
                upperChar = Character.toUpperCaseEx(srcChar); 
            } 
            if ((upperChar == Character.ERROR) 
                    || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) { 
                if (upperChar == Character.ERROR) { 
                    if (localeDependent) { 
                        upperCharArray = 
                                ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale); 
                    } else { 
                        upperCharArray = Character.toUpperCaseCharArray(srcChar); 
                    } 
                } else if (srcCount == 2) { 
                    resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount; 
                    continue; 
                } else { 
                    upperCharArray = Character.toChars(upperChar); 
                } 
                /* Grow result if needed */ 
                int mapLen = upperCharArray.length; 
                if (mapLen > srcCount) { 
                    char[] result2 = new char[result.length + mapLen - srcCount]; 
                    System.arraycopy(result, 0, result2, 0, i + resultOffset); 
                    result = result2; 
                } 
                for (int x = 0; x < mapLen; ++x) { 
                    result[i + resultOffset + x] = upperCharArray[x]; 
                } 
                resultOffset += (mapLen - srcCount); 
            } else { 
                result[i + resultOffset] = (char)upperChar; 
            } 
        } 
        return new String(result, 0, len + resultOffset); 
    } 
    public String toUpperCase() { 
        return toUpperCase(Locale.getDefault()); 
    } 

23、String 为什么是不可变的

  • String 不可变是因为在 JDK 中 String 类被声明为一个 final 类,且类内部的 value 字节数组也是 final 的,只有当字符串是不可变时字符串池才有可能实现,字符串池的实现可以在运行时节约很多 heap 空间,因为不同的字符串变量都指向池中的同一个字符串;
  • 如果字符串是可变的则会引起很严重的安全问题,譬如数据库的用户名密码都是以字符串的形式传入来获得数据库的连接,或者在 socket 编程中主机名和端口都是以字符串的形式传入,因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子改变字符串指向的对象的值造成安全漏洞;
  • 因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享,这样便不用因为线程安全问题而使用同步,字符串自己便是线程安全的;
  • 因为字符串是不可变的所以在它创建的时候 hashcode 就被缓存了,不变性也保证了 hash 码的唯一性,不需要重新计算,这就使得字符串很适合作为 Map 的键,字符串的处理速度要快过其它的键对象,这就是 HashMap 中的键往往都使用字符串的原因;

img

总结

StringBuffer、StringBuilder和String一样,也用来代表字符串。String类是不可变类,任何对String的改变都 会引发新的String对象的生成;StringBuilder则是可变类,任何对它所指代的字符串的改变都不会产生新的对象,而StringBuilder则是线程安全版的StringBuilder;

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Applet钢琴模拟程序java码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同的数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程接口的引用,用远程接口的引用访问EJB。 EJB中JNDI的使用码例子 1个目标文件,JNDI的使用例子,有代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它的主要作用是供程序使用的。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 的不同需求。例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密码实例 1个目标文件 摘要:Java码,算法相关,非对称加密   Java非对称加密程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三的密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java码,算法相关,密钥   Java生成密钥、保存密钥的实例码,通过本码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码的字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java码,文件操作,数据压缩,文件传输   Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java码,文件操作,图片水印   util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转等,可以参考代码加以改进做成小工具。 Java右键弹出菜单码 简单 Java圆形按钮实例代码,含注释 两个目标文件,自绘button。 Java圆形电子时钟代码 1个目标文件 内容索引:JAVA码,系统相关,电子钟   用JAVA编写的指针式圆形电子钟,效果图如下所示,其实代码很简单,希望对你有帮助。 Message-Driven Bean EJB实例代码 2个目标文件 摘要:Java码,初学实例,EJB实例   Message-Driven Bean EJB实例代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式   //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener   在对象创建的过程中将被容器调用,onMessage函数方法接收消息参数,将其强制转型为合适的消息类型,同时打印出消息的内容。同时一个mail note将被发送给消息发送者,发送一个e-mail通知给由recipient参数确定的e-mail账号,查询mail 服务器的会话……   还包括消息客户端程序,通过连接创建会话。创建发送者和映射消息。发送消息,同时对文本进行少量修改,发送end-of-messages消息,最后关闭连接。 Tcp服务端与客户端的JAVA实例代码 2个目标文件 摘要:Java码,文件操作,TCP,服务器   Tcp服务端与客户端的JAVA实例代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3个目标文件 第一步:运行ServerData.java 启动服务器,然后服务器处于等待状态 第二步:运行LoginData.java 启动(客户端)登陆界面 输入用户名 ip为本机localhost 第三步:在登陆后的界面文本框输入文本,然后发送 可以同时启动多个客户端 实现群聊。 浮动的广告 嵌套在html中 各种EJB之间的调用示例 7个目标文件 摘要:Java码,初学实例,EJB调用实例   各种EJB之间的调用码示例,用远程接口的引用访问EJB、函数将被FirstEJB调用,同时它将调用secondEJB 基于JAVA的UDP服务器模型代码 2个目标文件 摘要:Java码,网络相关,UDP   基于JAVA的UDP服务器模型代码,内含UDP服务器端模型和UDP客户端模型两个小程序,向JAVA初学者演示UDP C/S结构的原理。 简单聊天软件CS模式 2个目标文件 一个简单的CS模式的聊天软件,用socket实现,比较简单。 凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 简单 EJB的真实世界模型(代码) 15个目标文件 摘要:Java码,初学实例,基于EJB的真实世界模型   基于EJB的真实世界模型,附代码,部分功能需JSP配合完成。 J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA码,综合应用,J2me游戏,PNG,图形处理   这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失。使用时候只需在控制台窗口执行jar就可以了。 Java 3DMenu 界面码 5个目标文件 内容索引:Java码,窗体界面,3DMenu   Java 3DMenu 界面码,有人说用到游戏中不错,其实平时我信编写Java应用程序时候也能用到吧,不一定非要局限于游戏吧,RES、SRC资都有,都在压缩包内。 Java zip压缩包查看程序码 1个目标文件 摘要:Java码,文件操作,压缩包查看   Java zip压缩包查看程序,应用弹出文件选择框,选择ZIP格式的压缩文件,可以像Winrar软件一样查看压缩文件内部的文件及文件夹,码截图如上所示。 Java 数字签名、数字证书生成码 2个目标文件 摘要:JAVA码,系统相关,数字签名,数字证书   Java 数字签名、数字证书的相关实例。   关于数字签名:产生RSA密钥对(myKeyPair),得到RSA密钥对,产生Signature对象,对用私钥对信息(info)签名,用指定算法产生签名对象,用私钥初始化签名对象,将待签名的数据传送给签名对象(须在初始化之后),用公钥验证签名结果,使用公钥初始化签名对象,用于验证签名。   数字证书:从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java码,初学实例,ajax,登录   一个Java+ajax写的登录实例,附有JAVA文件,JAVA新手朋友可以学习一下。 JAVA+JSP的聊天室 8个目标文件 简单 JavaScript万年历 显示出当前时间及年份,还可以选择年份及月份和日期 Java编写的HTML浏览器 一个目标文件 摘要:Java码,网络相关,浏览器   Java编写的HTML浏览器代码,一个很简单甚至不算是浏览器的HTML浏览器,使用方法:   可直接输入文件名或网络地址,但必需事先连入网络。 Java编写的山寨QQ,多人聊天+用户在线 21个目标文件 摘要:JAVA码,媒体网络,山寨QQ,Java聊天程序   Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构,   当用户发送第一次请求的时候,验证用户登录,创建一个该qq号和服务器端保持通讯连接得线程,启动该通讯线程,通讯完毕,关闭Scoket。   QQ客户端登录界面,中部有三个JPanel,有一个叫选项卡窗口管理。还可以更新好友列表,响应用户双击的事件,并得到好友的编号,把聊天界面加入到管理类,设置密码保护等。 Java编写的网页版魔方游戏 内容索引:JAVA码,游戏娱乐,魔方,网页游戏   Java编写的网页版魔方游戏,编译后生成.class文件,然后用HTML去调用,不过运行时候需要你的浏览器安装有运行Class的插件。Java代码实现部分,比较有意思,也具参考性。像坐标控制、旋转矩阵、定时器、生成图像、数据初始化、矩阵乘法、坐标旋转、判断是否是顺时针方向排列、鼠标按下、放开时的动作等,都可在本码中得以体现。 Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA码,系统相关,系统信息检测   用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作方法及代码 1个目标文件 摘要:Java码,初学实例,波浪文字   Java波浪文字,一个利用Java处理字符的实例,可以设置运动方向参数,显示文本的字符数组,高速文本颜色,显示字体的 FontMetrics对象,得到Graphics实例,得到Image实例,填充颜色数组数据,初始化颜色数组。 Java吃豆子游戏代码 6个目标文件 内容索引:JAVA码,游戏娱乐,JAVA游戏码   JAVA编写的吃豆子游戏,类似疯狂坦克一样,至少界面有点像。大家可以看截图。 Java从网络取得文件 1个目标文件 简单 Java从压缩包中提取文件 1个目标文件 简单 Java存储与读取对象 1个目标文件 如题 Java调色板面板代码 1个目标文件 摘要:Java码,窗体界面,调色板   使用Java语言编写的一款用于反映颜色变化的面板,也就是大家熟悉的颜色调色板演示程序。原理是初始化颜色选择按钮,然后为颜色选择按钮增加事件处理事件,最后实例化颜色选择器。 Java二进制IO类与文件复制操作实例 16个目标文件 内容索引:Java码,初学实例,二进制,文件复制   Java二进制IO类与文件复制操作实例,好像是一本书的例子,代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制代码 1个目标文件 摘要:Java码,文件操作,权限控制   Java访问权限控制,为Java操作文件、写入文件分配合适的权限,定义写到文件的信息、定义文件,输出到c:/hello.txt、写信息到文件、关闭输出流。 Java绘制图片火焰效果 1个目标文件 摘要:Java码,图形操作,火焰效果   Java绘制图片火焰效果,代码相关注释:前景和背景Image对象、Applet和绘制火焰的效果的Image对象、Applet和绘制火焰的效果的Graphics对象、火焰效果的线程、Applet的高度,图片到图片装载器、绘制火焰效果的X坐标,Y坐标、得到X坐标,Y坐标值、绘制火焰效果Image…… Java加密解密工具集 JCT v1.0码包 5个目标文件 内容索引:JAVA码,综合应用,JCT,加密解密   WDSsoft的一款免费代码 JCT 1.0,它是一个Java加密解密常用工具包。 Java局域网通信——飞鸽传书代码 28个目标文件 内容索引:JAVA码,媒体网络,飞鸽传书   Java局域网通信——飞鸽传书代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和客户端 2个目标文件,如题。 Java目录监视器程序 9个目标文件 内容索引:JAVA码,综合应用,目录监视   用JAVA开发的一个小型的目录监视系统,系统会每5秒自动扫描一次需要监视的目录,可以用来监视目录中文件大小及文件增减数目的变化。 Java日期选择控件完整代码 14个目标文件 内容索引:JAVA码,系统相关,日历,日期选择   Java语言开发的简洁实用的日期选择控件,码文件功能说明:   [DateChooser.java] Java 日期选择控件(主体类) [public]   [TablePanel.java] 日历表格面板   [ConfigLine.java] 控制条类   [RoundBox.java] 限定选择控件   [MonthMaker.java] 月份表算法类   [Pallet.java] 调色板,统一配色类 Java扫雷码 Java生成自定义控件代码 2个目标文件 Java实现HTTP连接与浏览,Java码下载 1个目标文件 摘要:Java码,网络相关,HTTP   Java实现HTTP连接与浏览,Java码下载,输入html文件地址或网址,显示页面和HTML文件,一步步的实现过程请下载本实例的Java码,代码中包括丰富的注释,对学习有帮助。 Java实现的FTP连接与数据浏览程序 1个目标文件 摘要:Java码,网络相关,FTP   Java实现的FTP连接与数据浏览程序,实现实例化可操作的窗口。   部分代码摘录:   ftpClient = new FtpClient(); //实例化FtpClient对象   String serverAddr=jtfServer.getText(); //得到服务器地址   String user=jtfUser.getText(); //得到用户名   String pass=jtfPass.getPassword().toString(); //得到密码   ftpClient.openServer(serverAddr); //连接到服务器   ftpClient.login(user,pass); //在服务器上注册   InputStream is=ftpClient.list(); //得到服务器目录与文件列表输入流   StringBuffer info=new StringBuffer(); //实例化StringBuffer对象,用于输出信息   int ch;   while ((ch=is.read())>=0){ //未读完列表,则继续   info.append((char)ch); //增加信息   …… Java实现的点对点短消息发送协议(smpp)开发包码 70个目标文件,如题。 Java实现的放大镜效果附有文件 1个目标文件 内容索引:Java码,初学实例,放大镜,哈哈镜   Java实现的放大镜效果附有文件,编译环境最近出了问题,因此没有测试,也没有抓到图,希望各位自行测试一下。 Java实现跟踪鼠标运行坐标的码 1个目标文件 内容索引:JAVA码,系统相关,鼠标钩子   Java编写的一个小程序,用以实现跟踪鼠标的运行位置(坐标),程序很小,很实用,暂时抓不到截图。 Java实现移动的遮照效果 1个目标文件 摘要:Java码,初学实例,遮照效果   Java实现移动的遮照效果,先实现椭圆形的遮罩,实例化媒体加载器,最后在创建缓冲区中的图像形成遮罩效果,而且它是会移动的。 Java鼠标拖拽功能 1个目标文件 Netbeans平台下实现的JAVA 拖放效果的一个实例,包括代码和所需的图片资。 (运行后会屏显示窗体,没有关闭按钮,可使用快捷键Ctrl + F4关闭~) Java图片倒影效果实例码 1个目标文件 摘要:Java码,图形操作,图片倒影   Java图片倒影效果实例码,有意思也很有参考价值的一个Java图像处理小程序,先读取图像然后进行图像重绘,产生倒影的效果,仅供参考。 java网络五子棋的代码 7个目标文件 AVA网络五子棋,实现基本功能,无多余花哨内容,适合大学生课程设计学习使用,内含完整可运行代码及运行指导视频,Eclipse环境。 Java文件选择器代码 2个目标文件 摘要:Java码,文件操作,文件选择器   Java文件选择器代码 Java文字跑马灯与信息窗口 1个目标文件 摘要:Java码,文件操作,跑马灯   Java文字跑马灯效果与信息窗口,将一段文字按照滚动的方式显示出来,在网页设计中比较常见,本例使用Java实现文字跑马灯效果。 Java写的ATM机取款模拟程序 9个目标文件 内容索引:JAVA码,综合应用,ATM,JAVA,模拟   基于Java技术,只实现了ATM机的取款过程,有兴趣和有能力的高手可以再加以改进,这样就更完美了。可作为Java初学者《面向对象》编程的一个很好范例。     在这个程序中,用到以下JAVA类库:      dataAccess(数据操作)类:包含用于数据库的相关操作   atmScreen(ATM屏幕)类:主要创建各操作窗体和相应按钮事件   Account(用户帐户)类:包含用户信息的验证、余额查询和扣钱等方法   readCard(读卡机)类:包含读取用户卡号和退卡(退出系统)   moneyMac(取钱机)类:只用于打印清单   Atm(系统)类:系统主方法的开始,负责调用其他类 Java写的巨型LCD液晶时钟显示屏 8个目标文件 内容索引:JAVA码,综合应用,电子钟,LCD,液晶   一个巨型LCD数字电子时钟,用JAVA写的,运行截图如上示。它还带有右键菜单,LCD颜色可以变换等。 Java用GZIP压缩解压文件 1个目标文件 摘要:Java码,文件操作,GZIP   Java使用GZIP压缩解压文件,如果你正在使用Java开发文件压缩或解压的功能,那么Gzip应该来说是比较值得参考的,那么本实例或许正是您需要的,Java基于Gzip的文件压缩与解压程序代码,供码下载者参考。 Java用Zip压缩多个文件实例码 1个目标文件 摘要:Java码,文件操作,压缩文件   Java用Zip压缩多个文件,一个Java文件操作小实例,用ZIP同进压缩多个文件,实际是打开文件读取,然后再利用ZipEntry实例化待压缩的条目列表,将ZIP条目列表写入输出流,从文件得到文件输入流,写入缓冲数据等。 Java游戏使命的召唤码 5个目标文件 内容索引:JAVA码,游戏娱乐,Java游戏码,使命的召唤   Java游戏使命的召唤码,又名:Call of Duty,MFORMA超精典游戏,有兴趣的可以重新编译学习一下。 Java码的仿QQ聊天程序 如题 Java中的Blowfish对称密钥加密算法类和实例 2个目标文件 内容索引:Java码,算法相关,Blowfish,JAVA加密,对称密钥算法   JAVA中的Blowfish加密属于对称密钥算法,如果知道密钥,则可以对加密后的数据解密,但如果如果不知道密钥,基本上是不可能的,因此,这就决定了它的先天不足,就是带来的密钥的管理问题。 Java中的SSL及HTTPS协议实例码 1个目标文件 摘要:Java码,网络相关,HTTPS协议   Java中的SSL及HTTPS协议实例码,使用SSL套接字的HTTPS服务器端,接受客户端的一个连接,并返回Hello,world.   本例中使用8080端口创建SSL服务器套接字,返回缺省的SocketFactory对象,生成PrintWriter对象,用于输出信息。 Java自定义光标程序码 1个目标文件 摘要:Java码,窗体界面,自定义光标   Java自定义光标程序码,将光标定义成其它形式的图标,利用ToolKit对象得到图像,实例化自定义光标对象,增加组件等。 Jav动画图标码(显示GIF图像) 1个目标文件 摘要:Java码,图形操作,动画图标   Jav动画图标码(显示GIF图像),学习如何连续加载GIF图像从而生成动画图标,先创建一个用于显示动画图标的数组,创建构造函数,初始化数组,重载组件绘制方法,实例化Timer对象显示动画,增加组件到窗口上。 JSP树型菜单 DTree html+js实现 Notebook码,Java记事本 2个目标文件 摘要:Java码,文字字符,Java记事本   Java记事本:Notebook码下载,虽然是个功能不多的记事本,但通过这个Java程序你可以学习到不少小技巧呢!比如创建界面、安装各种监听器,在窗体上布局主菜单,保存用户编辑的文件,以及如何使用"另存为"对话框保存文件,如何新建和打开一个文档等,代码内包括了相当多的注释,是Java新手学习JAVA编程的好范例。   当用户按下窗口的“关闭”时,会自动调用此方法。 PDF分割与合并代码 3个目标文件 能把一个PDF分割成多个单页的PDF,把多个PDF合并成一个PDF。 QR解码的Java实现程序 25个目标文件 内容索引:JAVA码,媒体网络,QR解码,Java   用Java实现QR解码的程序代码。 编译原理--LR(1)分析表构造(JAVA) 8个目标文件 如题 传奇私服登录器Java版附代码 2个目标文件,如题。 单机版java五子棋V1.1 5个目标文件 完整的单机版java五子棋游戏,主要是判定胜负的算法,使用数组进行遍历,很容易理解。 很强的Java加密解密算法码 3个目标文件 内容索引:Java码,算法相关,JAVA算法,加密解密   很强的JAVA加密、解密算法码,一共有6种算法可供选择,另外还可以直接生成ZIP压缩文件。 简单的注册与登录功能 6个目标文件 一个简单的用户登录界面 要连接数据库的 有登陆 注册功能 仅供初学者学习 简单模拟的J2ME潜艇大战代码 4个目标文件 内容索引:JAVA码,游戏娱乐,J2ME手机游戏,潜艇大战   简单模拟的J2ME手机游戏潜艇大战的代码,界面有些粗糙,不过基本功能都实现了,发弹,躲闪等,可以帮助新手提高J2ME技术。 局域网广播系统java码 如题 java游戏 可实现网上对战和人机对战 7个目标文件 雷电游戏JAVA版程序 8个目标文件 这是一个简单的Java仿雷电游戏(码见包内),共设置有三关三个小BOSS。采用有GreenJVM发布,因此可以运行在未装载JRE的Windows系统之上。 网络蚂蚁Java版 14个目标文件 用Java实现的网络蚂蚁,功能强大,方便上传下载,断点续传等操作 网页浏览器 如题 java学生成绩系统(图形界面) 14个目标文件 如题。 java学生课程管理系统 6个目标文件 如题。 一个较初级的EJB商业应用的例子 如题 一个支持servlet的web服务器 14个目标文件 如题。 用Java加密类实现DES、RSA及SHA的加密算法 9个目标文件 如题。 用java写的SFTP代码 用java实现的Tftp(Sftp)客户端与服务器程序。在这个程序中用到了一个“状态”的机制:客户端与服务器端在开始运行时有相同的状态,通过用户的输入或程序内部运行的机制,程序可以转到不同的状态,在不同的状态下程序实现了不同的功能。 用jdom解析xml 1个目标文件 要使用jdom解析xml文件,需要下载jdom的包,我使用的是jdom-1.1。解压之后,将lib文件夹下的.jar文件以及build文件夹下的jdom.jar拷贝到工程文件夹下,然后就可以使用jdom操作xml文件了。 copass代码 Compass是一个强大的,事务的,高性能的对象/搜索引擎映射(OSEM:object/search engine mapping)与一个Java持久层框架. Compass实现了通过注册Hibernate的相关事件实现了数据的实时索引.. DataBuffer在Java中使用ADO.NET 本码的作者对ADO.Net有着相当深厚的感情,有着对JAVA中DataBuffer类库运用的出色理解。它是开项目javadesktop中的一个子项目,通过它你可以真正的理解DataSet、DataTable、DataRow……类库的使用。对这方面不太熟的开发者绝对有帮助。 HAHA CHAT Java仿QQ聊天程序代码 iCHAT聊天室基于Java 内容索引:JAVA码,媒体网络,iChat,Java聊天室   iChat LE 1.1版码,一个比较大型的JAVA版聊天室程序,可能要用到DLL文件,压缩包内已经有了,一年前的程序。 IP定位器 J2ME黑白棋游戏手机版 v2.1完整码 J2ME冒险游戏CASPER代码 J2me月光战机游戏码 JasperReports 报表类库v3.5 Java24点游戏逼真图形版代码 Java 3D魔方游戏码及中文注释包 内容索引:JAVA码,游戏娱乐,JAVA3D,魔方游戏   很强的JAVA 3D魔方游戏,这是码及中文注释包,作者的开发文档和思路都在里面,对学习很有帮助! allin.dev 重载了ListView,更好的实现! copass代码 Java (Jsp)制作简单的表单程序 java Socket通信实现 Java 版的酒店系统,貌似完整 Java 电梯模拟程序 v2.0 Java 飞机订票 Java 高考信息管理系统 SQL数据库 java 一个消息发布网站 Java+MsSQL超市进销存(毕业设计及答辩资料) Java+sqlserver2000做的员工管理系统 Java+SQL信用卡管理系统代码 Java+XML日程提醒系统 Java+XML写的RSS阅读器 JAVA版Swing星际争霸游戏代码 Java半透明图片实现的步骤及代码 JAVA帮助视图组件库 Help GUI 1.1代码 Java毕业论文:搜索引擎系统附代码 JAVA毕业设计_员工管理系统含文档 Java毕业设计一款J2me飞行射击游戏 Java仓库管理系统,Access数据库 Java超市管理,SQL2000+代码 Java超市进销存系统 Java大型CERP进销存系统 Java电子相册码 Java赌神游戏网络版代码 JAVA短信网关平台(值得一看) Java多用户聊天室程序(毕业设计) Java仿Vista界面风格的登录窗口 Java仿千千静听音乐播放器代码 Java火影忍者游戏代码 Java机车狂飙代码 JAVA开发的打字软件程序 Java开发的简单WEB服务器码 Java聊天程序(JBuilder) Java聊天软件Visual Chat v1.91码 Java模仿的MSN聊天软件 Java企业人事管理系统码 JAVA轻量级的MVC框架应用实例 Java软件度量码 Java声音播放程序代码 JAVA实现CLDC与MIDP底层编程的代码 JAVA实现超级玛丽 Java实现的视频播放程序码 Java手机短信项目码 Java手机游戏大富翁代码+注释 Java手机与计算机互发彩信码 Java坦克大战网络对战版代码 Java跳棋(基于SWT) Java通讯录手机版码 Java图片翻折,将图像压扁 Java图书馆管理系统程序 JAVA图书馆管理系统码 Java图像文件的缩小与放大 Java推箱子游戏(50关+音效) JAVA网络抓包程序 Java文件切割器代码 java项目码在线相册系统 Java写的天气预报软件 Java写的图片幻灯片切换特效 Java写的一个mp3播放器 Java学生信息管理系统码包 Java用的在线地图浏览模块 Java游戏沙丘城堡代码 Java游戏中斜视角编辑器及引擎代码 Java约瑟夫环演示Applet码 Java中的EJB编程实例代码 Java转换xml JLoading Java版的Mp3下载工具 JSP 动态数据菜单 JSP 学生管理系统(部代码+数据库) jsp+servlet+javabean+mysql党员信息管理系统 jsp高校科研项目管理系统 JSP开发的项目跟踪系统 jsp生产管理系统 msn聊天程序Java仿真代码 P2P--多用户在线聊天室(Java码) P2P码 Azureus 2.5.0.2(JAVA) Skype 4.0 Java版码及开发文档 SnakeScript Java游戏脚本引擎 v1.1 Tsinghua IP 清华大学学生写的一个有关IP的Java程序 Visualvm 基于JAVA的CPU硬件资管理器程序 weblogic+j2ee构建音乐网站(原代码+数据库) web综合教学管理系统 YOYOPlayer 基于Java的网络播放器代码 宾馆管理系统 餐饮门户 超市购物系统 车间管控 打地鼠游戏 单位固定资产登记管理系统JAVA版 电子书店管理系统 分离SQL Server数据库 基于BS结构的Java可视化工作流定制软件 基于J2ME的Java游戏梦幻炸弹人程序 基于JAVA的ICQ系统 基于Java的mp3播放器代码 基于JAVA的日程提醒簿 基于Java的小型人事管理系统,带数据库 基于Java的邮件服务器程序 基于MVC的Java资管理器 v2.0 季风进销存管理系统(JSP版) 家庭多媒体播放器 开Winzip压缩工具Java版码 客户管理系统 Alfresco Content Management 乐趣大型购物系统 类似QQ的聊天软件JAVA版码(附设计文档) 连接postsql数据库的java代码 泡泡堂战车游戏JAVA版码 配置ODBC数据 企业进销存管理系统 轻松商城系统 手机游戏J2ME毕业设计 书籍管理系统 网络电视代码TV-Browser 蜀山剑侠传游戏J2ME手机版代码 网上书店 物业管理系统毕业设计+码 销售预测系统PDP系统 选修课程管理系统V1.2.3 阳光酒店管理系统 一款Java网络格斗游戏码 用iText类库制作PDF文档 用JAVA做的聊天软件,有安装程序和代码 在Servlet中连接数据库的Java代码 中国移动业务管理系统码(SSH框架)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个双鱼座的测开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值