差点忘了最常用的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相关方法。关于编码相关的知识,不是本文要讲的内容,大家自行查阅资料。

java基础类型源码解析之String的更多相关文章

  1. java基础类型源码解析之HashMap

    终于来到比较复杂的HashMap,由于内部的变量,内部类,方法都比较多,没法像ArrayList那样直接平铺开来说,因此准备从几个具体的角度来切入. 桶结构 HashMap的每个存储位置,又叫做一个桶 ...

  2. java集合类型源码解析之ArrayList

    前言 作为一个老码农,不仅要谈架构.谈并发,也不能忘记最基础的语言和数据结构,因此特开辟这个系列的文章,争取每个月写1~2篇关于java基础知识的文章,以温故而知新. 如无特别之处,这个系列文章所使用 ...

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

    今天我们来学习集合的第一大体系 List. List 是一个接口,定义了一组元素是有序的.可重复的集合. List 继承自 Collection,较之 Collection,List 还添加了以下操作 ...

  4. java集合类型源码解析之PriorityQueue

    本来第二篇想解析一下LinkedList,不过扫了一下源码后,觉得LinkedList的实现比较简单,没有什么意思,于是移步PriorityQueue. PriorityQueue通过数组实现了一个堆 ...

  5. 【Java实战】源码解析Java SPI(Service Provider Interface )机制原理

    一.背景知识 在阅读开源框架源码时,发现许多框架都支持SPI(Service Provider Interface ),前面有篇文章JDBC对Driver的加载时应用了SPI,参考[Hibernate ...

  6. Java 8 ThreadLocal 源码解析

    Java 中的 ThreadLocal是线程内的局部变量, 它为每个线程保存变量的一个副本.ThreadLocal 对象可以在多个线程中共享, 但每个线程只能读写其中自己的副本. 目录: 代码示例 源 ...

  7. Java泛型底层源码解析-ArrayList,LinkedList,HashSet和HashMap

    声明:以下源代码使用的都是基于JDK1.8_112版本 1. ArrayList源码解析 <1. 集合中存放的依然是对象的引用而不是对象本身,且无法放置原生数据类型,我们需要使用原生数据类型的包 ...

  8. Java集合---LinkedList源码解析

    一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...

  9. Java线程池源码解析

    线程池 假如没有线程池,当存在较多的并发任务的时候,每执行一次任务,系统就要创建一个线程,任务完成后进行销毁,一旦并发任务过多,频繁的创建和销毁线程将会大大降低系统的效率.线程池能够对线程进行统一的分 ...

随机推荐

  1. MACOS 安装mysqlclient 的 Library not loaded错误

    报错场景 >>> import MySQLdb Traceback (most recent call last): File "<stdin>", ...

  2. OpenStack kilo版(4) Glance部署

    Glance简介 Glance-api:接受云系统镜像的构建.删除.读取请求 Glance-Registry:云系统的镜像注册服务 部署在controller节点 配置数据库 MariaDB [(no ...

  3. Robo 3T SQL

    查询指定日期,指定显示字段,排序,注释功能 db.getCollection('spuBasisInfo') .find({"createTime":{$gte:ISODate(& ...

  4. JAVA笔记整理(六),JAVA中的多态

    JAVA引用变量有两个类型:一个是编译时类型,一个运行时类型 编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定.如果编译时类型和运行时类型不一样,就形成了多态. 因为子类其 ...

  5. vi编辑器简介

    vi编辑器是Linux和Unix上最基本的文本编辑器,工作在字符模式下.由于不需要图形界面,vi是效率很高的文本编辑器.尽管在Linux上也有很多图形界面的编辑器可用,但vi在系统和服务器管理中的功能 ...

  6. Vue中的button事件

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. Poj-3286- How many 0's? - 【基础数位DP】

    How many 0's? Description A Benedict monk No.16 writes down the decimal representations of all natur ...

  8. P1078 文化之旅[最短路]

    题目背景 本题是错题,后来被证明没有靠谱的多项式复杂度的做法.测试数据非常的水,各种玄学做法都可以通过(比如反着扫),不代表算法正确.因此本题题目和数据仅供参考. 题目描述 有一位使者要游历各国,他每 ...

  9. CORS通信

    CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing).它允许浏览器向跨域的服务器,发出XMLHttpRequest请 ...

  10. machine learning(14) --Regularization:Regularized linear regression

    machine learning(13) --Regularization:Regularized linear regression Gradient descent without regular ...