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

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

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拼接的效率较高。

时间: 2024-08-01 16:55:18

java String部分源码解析的相关文章

Java集合---LinkedList源码解析

一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clone()与toArray()9.遍历数据:Iterator()二.ListItr 一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> implements List&

Java 8 ThreadLocal 源码解析

Java 中的 ThreadLocal是线程内的局部变量, 它为每个线程保存变量的一个副本.ThreadLocal 对象可以在多个线程中共享, 但每个线程只能读写其中自己的副本. 目录: 代码示例 源码解析 InheritableThreadLocal ThreadLocalMap Get 流程 Set 流程 Remove 代码示例 我们编写一个简单的示例: import java.util.Random; import java.util.concurrent.ExecutorService;

Java之Object源码解析

Object类作为所有类层次的根源,有着非常重要的作用,每个类都让Object作为其超类,所有的对象包括数组,都实现了Object里面定义的方法,总之一句话,凡是有对象的地方就一定实现了Object类的方法 首先我们知道,Object类里有如下几种方法: Class<?> getClass();  //返回当前Object的运行类 int hashCode(); //返回该对象的哈希值 boolea equals(Object obj); // 比较其它对象是否与此对象相等 protected

JAVA常用集合源码解析系列-ArrayList源码解析(基于JDK8)

文章系作者原创,如有转载请注明出处,如有雷同,那就雷同吧~(who care!) 一.写在前面 这是源码分析计划的第一篇,博主准备把一些常用的集合源码过一遍,比如:ArrayList.HashMap及其对应的线程安全实现,此文章作为自己相关学习的一个小结,记录学习成果的同时,也希望对有缘的朋友提供些许帮助. 当然,能力所限,难免有纰漏,希望发现的朋友能够予以指出,不胜感激,以免误导了大家! 二.稳扎稳打过源码 首先,是源码内部的成员变量定义以及构造方法: 1 /** 2 * Default in

java IO 包源码解析

本文参考连接:http://blog.csdn.net/class281/article/details/24849275                         http://zhhphappy.iteye.com/blog/1562427 一.IO包简要类图 Java I/O流部分分为两个模块,即Java1.0中就有的面向字节的流(Stream),以及Java1.1中大幅改动添加的面向字符的流(Reader & Writer).添加面向字符的流主要是为了支持国际化,旧的I/O流仅支持

java String部分源码学习记录

public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /**char数组用于字符的存储 */ private final char value[]; /** 缓存string的hash码 */ private int hash; // Default to 0 public String() {/**无参构造函数,打印值为""*/ this.

Java之HashMap源码解析1

讲解HashMap<K,V>时,我们先看看在API文档中是怎么介绍的: 基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用 null 值和null 键.(除了非同步和允许使用 null 之外,HashMap 类与 Hashtable 大致相同.)此类不保证映射的顺序,特别是它不保证该顺序恒久不变. 此实现假定哈希函数将元素适当地分布在各桶之间,可为基本操作(get 和 put)提供稳定的性能.迭代collection 视图所需的时间与 HashMap 实例的"

Java基础——集合源码解析 List List 接口

今天我们来学习集合的第一大体系 List. List 是一个接口,定义了一组元素是有序的.可重复的集合. List 继承自 Collection,较之 Collection,List 还添加了以下操作方法 位置相关:List 的元素是有序的,因此有get(index).set(index,object).add(index,object).remove(index) 方法. 搜索:indexOf(),lastIndexOf(); 迭代:使用 Iterator 的功能板迭代器 范围性操作:使用 s

Java集合-09LinkedHashMap源码解析及使用实例

LinkedHashMap 简介 hash表和链表实现了map接口,迭代顺序是可以预测的.LinkedHashMap和HashMap的不同是它所有的entry 维持了一个双向链表结构.该链表定义了通常迭代顺序是键插入的顺序. LinkedHashMap 定义 public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V> 继承HashMap类,表明对于HashMap的操作LinkedHas