`
leonzhx
  • 浏览: 793477 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

读 String原代码

阅读更多

1.  CharSequence接口定义了一个只读的char序列。String 实现 CharSequence , Serializable , Comaprable<String>


2.  由 char[] value, int offset, int count 和 int hash组成。


3.  构造函数 public String(String original) 基本上来说是没用的,因为String本身是immutable的,没必要copy一下。但有一个用处:节省空间。比如说,你用subString生成的一个String,它是重用原来的char[]的,而原来的那个String你已经不想用了(这个条件很重要), 你可以用这个构造函数重建一个String来释放空间。

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

 

4.  提供了一组构造函数,按照给定的Charset来将一个byte 数组 decode成一个字符串。


5.  接收StringBuilder或StringBuffer的构造函数,会将StringBuilder或StringBuffer先toString() 然后将新生成的String中的value , offset 和count赋值给当前String,这时会将char array拷贝一份,所以之后StringBuilder或StringBuffer的修改不会影响到生成的String。但问题是这样不就多生成了一个String对象么?


6.  length()返回的是count的值,也就是说是Code Unit的个数,而不是Code Point的个数, 对于Supplementary Character这个length()不是字符个数。如果想得到Code Point的个数可以使用codePointCount方法。


7.  getBytes方法,当不传Charset时就用系统默认的Charset将字符串转成相应的编码。


8. public boolean contentEquals(StringBuffer sb) 对 sb作了同步,防止sb中途被修改:

 

public boolean contentEquals(StringBuffer sb) {
        synchronized(sb) {
            return contentEquals((CharSequence)sb);
        }
    }
 

 

9.  public boolean contentEquals(CharSequence cs) 对StringBuilder和StringBuffer做了特殊处理,这样就避免在调用StringBuilder或StringBUffer的charAt方法时做的边界检查了:

 

public boolean contentEquals(CharSequence cs) {
        if (count != cs.length())
            return false;
        // Argument is a StringBuffer, StringBuilder
        if (cs instanceof AbstractStringBuilder) {
            char v1[] = value;
            char v2[] = ((AbstractStringBuilder)cs).getValue();
            int i = offset;
            int j = 0;
            int n = count;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
        // Argument is a String
        if (cs.equals(this))
            return true;
        // Argument is a generic CharSequence
        char v1[] = value;
        int i = offset;
        int j = 0;
        int n = count;
        while (n-- != 0) {
            if (v1[i++] != cs.charAt(j++))
                return false;
        }
        return true;
    }
 

 

10. 当作Case Insensitve比较时代价有点高:

public boolean regionMatches(boolean ignoreCase, int toffset,
                           String other, int ooffset, int len) {
        char ta[] = value;
        int to = offset + toffset;
        char pa[] = other.value;
        int po = other.offset + ooffset;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0) || (toffset > (long)count - len) ||
                (ooffset > (long)other.count - len)) {
            return false;
        }
        while (len-- > 0) {
            char c1 = ta[to++];
            char c2 = pa[po++];
            if (c1 == c2) {
                continue;
            }
            if (ignoreCase) {
                // 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;
    }
 

 

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

 

 

12.  String, StringBuilder和StringBuffer 共享了一段indexOf的逻辑:

static int indexOf(char[] source, int sourceOffset, int sourceCount,
                       char[] target, int targetOffset, int targetCount,
                       int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            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;
    }
 

 由此可见,想让indexOf(String substr, int fromIndex) 返回String.length()的唯一方法是, fromIndex >= String.length(),并且子串为空串。


13.  lastIndexOf写得有点奇怪:

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

 不是很理解为什么一定要从最后一个字符开始比较,虽然是last index,但匹配字符串没必要从最后一个字符开始比较,而且还用了一个让人不是很舒服的label。我也试着写了一个,才发现,其实要写得逻辑很严密还是需要费一番周折的:

private static int myLastIndexOf(char[] source, int sourceOffset,
			int sourceCount, char[] target, int targetOffset, int targetCount,
			int fromIndex) {

		if (fromIndex < 0) {
			return -1;
		}

		int rightIndex = sourceCount - targetCount;

		if (fromIndex > rightIndex) {
			fromIndex = rightIndex;
		}

		if (targetCount == 0) {
			return fromIndex;
		}

		char firstChar = target[targetOffset];
		int max = targetOffset + targetCount;

		for (int i = sourceOffset + fromIndex; i >= sourceOffset; i--) {
			if (source[i] != firstChar) {
				while (--i >= sourceOffset && source[i] != firstChar)
					;
			}

			if (i >= sourceOffset) {
				int j = targetOffset + 1;
				for (int k = i + 1; j < max && source[k] == target[j]; k++, j++)
					;

				if (j == max) {
					return i - sourceOffset;
				}
			}

		}
		return -1;

	}
 

 

14.  subString重用了原来的char[]。


15. public String replace(CharSequence target, CharSequence replacement) 是纯字面的匹配。replace方法中除了replaceFirst以外都是找出所有匹配的进行替换。


16.  trim把比空格小的unicode都当成空白了:

public String trim() {
        int len = count;
        int st = 0;
        int off = offset;      /* avoid getfield opcode */
        char[] val = value;    /* avoid getfield opcode */

        while ((st < len) && (val[off + st] <= ' ')) {
            st++;
        }
        while ((st < len) && (val[off + len - 1] <= ' ')) {
            len--;
        }
        return ((st > 0) || (len < count)) ? substring(st, len) : this;
    }
 

 

17.  intern 方法的注释很精确了:

 Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String .

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and t , s.intern() == t.intern() is true if and only if s.equals(t) is true .

All literal strings and string-valued constant expressions are interned.


17.  最后写了两个test case :

@Test
	public void testString() {
				
		String str = new String("ABC");
		String str1 = new String("ABC");
		
		assertFalse(str == str1);
		assertTrue(str.intern() == str1.intern());
		assertEquals(str.length(), str.indexOf("", str.length()));
		assertEquals("ss", "\\w\\w".replace((CharSequence)"\\w", "s"));
		
	}
 
0
0
分享到:
评论

相关推荐

    std::string format格式化函数源代码及两种格式化方法

    源代码主要分布在`str.hpp`和`string_format.cpp`这两个文件中。 在`str.hpp`文件中,`format`函数可能被定义为一个模板函数,接受各种类型的参数,并将它们转换为字符串进行格式化。这个函数通常会利用`std::...

    java8源代码内容

    这个压缩包文件“jdk1.8”包含了Java 8的源代码,这对于开发者来说是一个宝贵的资源,可以深入理解其内部工作原理,帮助在实际项目中更高效地使用Java 8的功能。 首先,Java 8的最重要的新特性之一是Lambda表达式。...

    文本编辑器源代码C代码

    文本编辑器源代码C代码 本资源是一个文本编辑器的源代码,使用C语言编写,包含了文本编辑器的基本功能,例如编辑、保存、加载、查找、替换等。下面是对该资源的详细解读: 标题:文本编辑器源代码 该标题表明了该...

    JSP目录直读程序源代码.zip

    **JSP目录直读程序源代码** 在Java Web开发中,JSP(JavaServer Pages)是一种用于创建动态网页的技术,它允许开发者将HTML代码与Java代码结合在一起,从而实现服务器端的数据处理和业务逻辑。本资源提供的“JSP...

    C#开发实战1200例源代码.zip

    《C#开发实战1200例源代码》是一个涵盖了大量C#编程实践案例的资源集合,对于初学者和有经验的开发者来说都是一个宝贵的参考资料。这个压缩包中包含的源代码实例覆盖了C#语言的各个核心概念,以及.NET框架的应用。...

    精通C#(第6版)源代码

    本资源包含该书的源代码,旨在帮助读者更好地理解和实践书中的示例,提升编程技能。 在C#的学习过程中,源代码是至关重要的,它能让我们直观地看到程序的结构和工作方式。C#第6版引入了许多新的特性,如自动属性...

    文件读取源代码文件读取源代码

    根据给定的信息,我们可以分析并总结出以下与文件读取及源代码相关的知识点: ### 1. 文件操作基础 在程序设计中,文件操作是非常重要的一个环节,它可以帮助我们保存数据到磁盘或者从磁盘读取数据。C++提供了多种...

    图书管理系统源代码

    代码有详细的解释 压缩包里面也有 数据库的文件 代码里设置的数据库 用户是 sa 密码是 123456 请使用的时候做相关的修改 下面给出 一部分的代码 请继续关注本资源的发布 会后面有很多实用的代码上传 using System....

    读DBC文件源代码

    在给定的`vehicleparam.c`和`vehicleparam.h`源代码文件中,我们可以预期它们实现了读取DBC文件的核心功能。以下是一些可能包含的关键函数和数据结构: 1. **数据结构定义**:首先,你需要定义表示DBC文件内容的...

    读文件C++源代码 VC6.0实现

    在本教程中,我们将探讨如何在Visual C++ 6.0环境下编写C++源代码来实现文件读取。VC6.0是微软早期的一款集成开发环境(IDE),虽然现在已经有些过时,但它仍然是学习C++基础的好工具。 1. **打开文件**:在C++中,...

    C语言源代码

    熟悉这些基本元素是读懂任何C语言源代码的前提。 2. **指针**:C语言中的指针是其强大之处,它们允许直接操作内存地址,实现高效的数据操作和动态内存管理。理解指针的声明、赋值、解引用以及指针与数组、函数的...

    C++编写的操作系统日志程序源代码

    本压缩包包含了一个用C++语言编写的操作系统日志程序的源代码,这对于学习C++编程以及操作系统日志管理具有很高的价值。 在C++中编写操作系统日志程序,通常涉及以下几个关键知识点: 1. **文件I/O操作**:日志...

    JAVA上百实例源码以及开源项目源代码

    Message-Driven Bean EJB实例源代码 2个目标文件 摘要:Java源码,初学实例,EJB实例 Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式 //给客户发一个感谢...

    加密文件 C#源代码

    在给定的"加密文件 C#源代码"主题中,我们可以深入探讨C#编程语言如何用于文件加密,特别是在Visual Studio 2005环境下。C#是一种面向对象的编程语言,由微软开发,广泛应用于构建Windows桌面应用、Web应用和服务。...

    文件读写 java 源代码

    ### 文件读写 Java 源代码知识点解析 #### 一、概述 在Java编程语言中,文件读写是一项基本而重要的功能。对于初学者来说,理解如何进行文件的输入输出操作至关重要。本篇文章将深入分析一段简单的Java源代码,该...

    spring源代码解析

    从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上...

    源代码加亮class.1.0.0

    1) 直接读源代码文件时 1. 根据扩展名适用不同的加亮规则 $stx = new STX(); echo $stx-&gt;stx_file($file); 2. 指定一个规则 $stx = new STX('perl'); echo $stx-&gt;stx_file($file); 2) 加亮字符串时: $stx...

    C#从入门到精通源代码2

    《C#从入门到精通源代码2》是一个学习C#编程语言的重要资源,它包含了多个逐步进阶的示例和项目,旨在帮助初学者和有经验的开发者深化对C#的理解。C#是一种多范式、面向对象的编程语言,由微软开发并广泛应用于...

    汇编语言读寄存器内容的源代码

    标题中的“汇编语言读寄存器内容的源代码”是指使用汇编语言编写的一段程序,该程序能够读取CPU寄存器的值,并将其转换为ASCII码形式存储或输出。描述中提到的环境是WINXP操作系统下,使用MASM5.0汇编器进行编译,...

    包含vb各种基本编程知识的例题及源代码

    这个压缩包"包含vb各种基本编程知识的例题及源代码",显然是一份丰富的学习资源,旨在帮助初学者理解和掌握VB编程的基础概念。通过实例和源代码,你可以亲手实践,从而更好地消化理论知识。 首先,VB的基本结构包括...

Global site tag (gtag.js) - Google Analytics