java String部分源码解析详解编程语言

String类型的成员变量

/** String的属性值 */   
    private final char value[]; 
 
    /** The offset is the first index of the storage that is used. */ 
    /**数组被使用的开始位置**/ 
    private final int offset; 
 
    /** The count is the number of characters in the String. */ 
    /**String中元素的个数**/ 
    private final int count; 
 
    /** Cache the hash code for the string */ 
   /**String类型的hash值**/ 
    private int hash; // Default to 0 
 
    /** use serialVersionUID from JDK 1.0.2 for interoperability */ 
    private static final long serialVersionUID = -6849794470754667710L;

   有上面的成员变量可以知道String类的值是final类型的,不能被改变的,所以只要一个值改变就会生成一个新的String类型对象,存储String数据也不一定从数组的第0个元素开始的,而是从offset所指的元素开始。

如下面的代码是生成了一个新的对象,最后的到的是一个新的值为“bbaa”的新的String的值。

     String a = new String("bb"); 
     String b = new String("aa"); 
     String c =  a + b;    

 

  也可以说String类型的对象是长度不可变的,String拼接字符串每次都要生成一个新的对象,所以拼接字符串的效率肯定没有可变长度的StringBuffer和StringBuilder快。

 

然而下面这种情况却是很快的拼接两个字符串的:

    String a = "aa" + "bb";

  原因是:java对它字符串拼接进行了小小的优化,他是直接把“aa”和“bb”直接拼接成了“aabb”,然后把值赋给了a,只需生成一次String对象,比上面那种方式减少了2次生成String,效率明显要高很多。

 


 

下面我们来看看String的几个常见的构造方法

 

1、无参数的构造方法:

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

 

 

2、传入一个Sring类型对象的构造方法

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; 
    }

 

 

 3、传入一个字符数组的构造函数

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

 

 

4、传入一个字符串数字,和开始元素,元素个数的构造函数

public String(char value[], int offset, int count) { 
        if (offset < 0) { 
            throw new StringIndexOutOfBoundsException(offset); 
        } 
        if (count < 0) { 
            throw new StringIndexOutOfBoundsException(count); 
        } 
        // Note: offset or count might be near -1>>>1. 
        if (offset > value.length - count) { 
            throw new StringIndexOutOfBoundsException(offset + count); 
        } 
        this.offset = 0; 
        this.count = count; 
        this.value = Arrays.copyOfRange(value, offset, offset+count); 
    }

 

   由上面的几个常见的构造函数可以看出,我们在生成一个String对象的时候必须对该对象的offset、count、value三个属性进行赋值,这样我们才能获得一个完成的String类型。

 


 

常见函数:

 

1、判断两个字符串是否相等的函数(Equal):其实就是首先判断比较的实例是否是String类型数据,不是则返回False,是则比较他们每一个字符元素是否相同,如果都相同则返回True,否则返回False

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; 
    }

 

 

 2、比较两个字符串大小的函数(compareTo):输入是两个字符串,返回的0代表两个字符串值相同,返回小于0则是第一个字符串的值小于第二个字符串的值,大于0则表示第一个字符串的值大于第二个字符串的值。

  比较的过程主要如下:从两个字符串的第一个元素开始比较,实际比较的是两个char的ACII码,加入有不同的值,就返回第一个不同值的差值,否则返回0

java String部分源码解析详解编程语言

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; 
    }

View Code

 

 

 3、判断一个字符串是否以prefix字符串开头,toffset是相同的长度

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; 
    } 
 
 public int hashCode() { 
 int h = hash; 
 if (h == 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; 
    }

 

 

 4、连接两个字符串(concat)

public String concat(String str) { 
 int otherLen = str.length(); 
 if (otherLen == 0) { 
     return this; 
 } 
 char buf[] = new char[count + otherLen]; 
 getChars(0, count, buf, 0); 
 str.getChars(0, otherLen, buf, count); 
 return new String(0, count + otherLen, buf); 
    }

 

 

 连接字符串的几种方式

1、最直接,直接用+连接

     String a = new String("bb"); 
     String b = new String("aa"); 
     String c =  a + b;

 

 

 2、使用concat(String)方法

      String a = new String("bb"); 
      String b = new String("aa");  
      String d = a.concat(b);

 

 

3、使用StringBuilder

 String a = new String("bb"); 
 String b = new String("aa"); 
      
StringBuffer buffer = new StringBuffer().append(a).append(b);

 

   第一二中用得比较多,但效率比较差,使用StringBuilder拼接的效率较高。

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/15154.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论