zoukankan      html  css  js  c++  java
  • java基础类型源码解析之String

    差点忘了最常用的String类型,我们对String的大多数方法都已经很熟了,这里就挑几个平时不会直接接触的点来解析一下。

    先来看看它的成员变量

    public final class String  {
        private final char value[];
        private int hash; // Default to 0
    }
    
    • string的内容其实就是一个char数组;
    • hash字段缓存了string的哈希值,因为string经常作为hashmap的key,这样能提高性能;

    hashCode

    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
    
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
    

    String的哈希值采用一种延迟计算的策略,计算方法很简单,就是把每个char都当做int,通过公式h=31*h+char的计算最终值。由于String是不可变对象,在生命周期内,hash值只需要计算一次。

    subString

    public String substring(int beginIndex, int endIndex) {
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }
    public String(char value[], int offset, int count) {
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
    
    

    注:上面的代码为了节省空间,省略了异常检查逻辑

    subString会创建一个全新的字符串,而不是共享原字符串的char数组。按道理讲,由于String是不可变的,那么subString和原string共享char数组是安全的,可能是出于其他方面的考虑:虽然节省了一点空间,但是需要额外增加一个offset和size成员,整体效率未必更佳。

    码点(CodePoint)

    简单介绍一下码点和码元的概念,一个码点是某种字符编码方案里面,某个字符对应的绝对编码值。而码元则是指具体的字符存储方案下,最小的存储单元。

    对java的String来说,存储的是unicode字符,使用的编码方案是utf-16,码元是char(16bit); utf-16的大部分码点用一个char足够了,但是有少部分需要两个char。

    我们来看一段从码点序列创建String的代码:

    public String(int[] codePoints, int offset, int 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));
        }
    
        // Pass 2: Allocate and fill in char[]
        final char[] v = new char[n];
    
        for (int i = offset, j = 0; i < end; i++, j++) {
            int c = codePoints[i];
            if (Character.isBmpCodePoint(c))
                v[j] = (char)c;
            else
                Character.toSurrogates(c, v, j++);
        }
    
        this.value = v;
    }
    
    • 同样,上面的代码删除了异常处理逻辑;

    • 请注意,码点用int来表示

    • 第一个循环,计算码点数组codePoints,需要多少长度的char数组:

      • Character.isBmpCodePoint 判断是否一个基本多文种平面码点,这样的码点只需1个char
      • 否则需要两个码点,长度+1
    • 第二个循环,把码点值经过转换存入char数组

      • 如果是基本码点,直接放入
      • 如果是非基本码点,需要做一个计算,生成两个char

    因此,如果你要把String当做一段实际的文本,并处理当中的单个文字,通过遍历char的方式是不行的,而要使用codePoint相关方法。关于编码相关的知识,不是本文要讲的内容,大家自行查阅资料。

  • 相关阅读:
    服务器设计之请求处理框架[转]
    为 Linux 应用程序编写 DLL[转]
    C语言编程技巧-signal(信号)[转]
    __thread关键字[转]
    iOS打电话、发短信、发邮件功能
    apple swift 初探
    cocos2d-x 3.x build 问题
    如何在WebApi中使用过滤器实现面向切面编程(AOP)
    Web API相对WCF优势,以及构建WebApi
    mvc中利用Attribute特性来进行进行简单的登陆验证
  • 原文地址:https://www.cnblogs.com/longhuihu/p/11132362.html
Copyright © 2011-2022 走看看