差点忘了最常用的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. java输出月的日历控制台

    LocalDate date=LocalDate.now(); int month=date.getMonthValue(); int today=date.getDayOfMonth(); date ...

  2. 云端的ABAP Restful服务开发

    愉快的暑假结束了,今天是小朋友新学期开学后的第一个周日,不知道各位家长是否和小朋友们一起,已经适应了新学期的生活了么? Jerry从少的可怜的属于自己的周末时光挤了一小部分时间出来,写了这篇文章. J ...

  3. Linux 终端下的颜色

    Linux 终端下颜色的输出 在命令行下也能产生五颜六色的字体和图案,只需要加上一些颜色代码,例如 echo -e "\033[41;36m 红底绿字\033[0m" 其中41的位 ...

  4. IO模型之NIO代码及其实践详解

    一.简介 NIO我们一般认为是New I/O(也是官方的叫法),因为它是相对于老的I/O类库新增的( JDK 1.4中的java.nio.*包中引入新的Java I/O库).但现在都称之为Non-bl ...

  5. 元类编程--__get__ __set__属性描述符

    from datetime import date, datetime import numbers class IntField: #数据描述符,实现以下任意一个,都会变为属性描述符 def __g ...

  6. 国内首本免费深度学习书籍!还有人没Get么?

    这本书的作者很有趣鸭. 一开篇别的不说,先跟大家讲哲学,讨论人工智能实现的可能性.摘录一些他的结论: 人工智能可以实现 自由意志并不存在 量子力学并不能证明自由意志的存在 幸福感和物质水平提高并没有绝 ...

  7. SpringBoot下,@WebFilter配置获取日志

    CREATE TABLE [dbo].[SWEBSERVICELOG]( [WLG_ID] [varchar](100) NOT NULL, [WLG_SESSIONID] [varchar](100 ...

  8. 用 Redis 实现延时任务

    原文:https://cloud.tencent.com/developer/article/1358266 1.什么是延时任务 延时任务,顾名思义,就是延迟一段时间后才执行的任务.延时任务的使用还是 ...

  9. k8s的高可用

    一.高可用原理   配置一台新的master节点,然后在每台node节点上安装nginx,nginx通过内部的负载均衡将node节点上需要通过访问master,kube-apiserver组件的请求, ...

  10. 大数据之路week07--day04 (YARN,Hadoop的优化,combline,join思想,)

    hadoop 的计算特点:将计算任务向数据靠拢,而不是将数据向计算靠拢. 特点:数据本地化,减少网络io. 首先需要知道,hadoop数据本地化是指的map任务,reduce任务并不具备数据本地化特征 ...