Java源码赏析(三)初识 String 类
由于String类比较复杂,现在采用多篇幅来讲述
这一期主要从String使用的关键字,实现的接口,属性以及覆盖的方法入手。省略了大部分的字符串操作,比如split()、trim()、replace()、contains()、matches()等。
在Java源码赏析(五)中,会增加对String类中的字符串操作进行详细描述,敬请期待。
今后,还会介绍StringBuffer、StringBuilder两个类。
/**
* 精简的String结构,便于我们初步的理解, 省略了大部分构造方法和字符串操作
* 使用了final关键字,说明此类是最终类,无法继承
* 实现了序列化接口,排序接口,CharSequence接口
*/
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; private int hash; // Default to 0 private static final long serialVersionUID = -6849794470754667710L; /** 指明需要实例化的字段 */
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0]; /** 省略CaseInsensitiveComparator()的实现,主要是用于按ASCII码的排序规则进行排序 */
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator(); /** 实现Comparable<String>,可用于集合类的排序功能 */
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value; int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
} /** 覆盖hashCode(),可以用于switch以及Map,Set的查询 */
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;
} /** 覆盖父类equal(),实现了值比较 */
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
} /** 覆盖父类toString() */
public String toString() {
return this;
} /**
* 实现CharSequence接口
* 共有length(), charAt(int index), subSequence(int beginIndex, int endIndex) 等
* 在实现subSequence()方法时使用了String中substring()方法
*/ /** 获取字符串长度 */
public int length() {
return value.length;
} /** 获取index位置的字符 */
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
} /** 获取字符串子串 */
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
} /** 从索引位置beginIndex到endIndex处获取子串 */
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen);
}
}
/** 若不存在,将字符串存入常量池并返回在常量池的引用;若已存在,则直接返回字符串的引用 */
public native String intern();
阅读一个类的源码,首先要定性。
1. 它是一个final的类,说明不可继承,
2. value为final,说明值创建后不可更改。
好处在于简单(不用考虑并发问题),安全(不用考虑子类、值被修改等问题),高效(由于不可变可以设计常量池的处理)等。
大概了解了String的属性和方法,我们回顾源码赏析一、二的内容,发现前两篇内容无一不体现在这个类中。希望大家可以结合前两篇来看待这个经典的类。
一、Object中的重写方法 equals()、 hashCode()、 toString()
二、常见的接口Serializable, Comparable的实现
除了上面两点之外,还实现了CharSequence这个字符串的通用接口。StringBuffer、StringBuilder也实现了此接口。
还有需要注意的一点是,字符串拥有 “操作符重载” 了 "+"。我们可以方便的使用这个操作符进行一些处理。
比如 连接字符串
String a = "hello";
String b = ", world";
//输出 hello, world
//
System.out.println(a + b);
注, “+” 最后不好放在for循环之中(第一种写法创建了100个对象),而第二种只创建了1个对象
String s = new String();
for(int i=0; i<100; i++) {
s = s + i;
}
//等效于
StringBuilder s1 = new StringBuilder();
for(int i=0; i<100; i++) {
StringBuilder one = new StringBuilder(i);
s1.append(one).toString();
}
//高效写法
StringBuilder s2 = new StringBuilder();
for(int i=0; i<100; i++) {
s2 = s2.append(i);
}
同理,频繁使用的String也可以直接写出 String s3 = "a";,不需要new出来 String s4 = new String("a");,这样能让这个值存在于常量池里(可以当成存在缓存)。
Java源码赏析(三)初识 String 类的更多相关文章
- Java源码赏析(五)再识 String 类
在 Java源码赏析(三)初识 String 类 中,我们已经大概理解了String的接口,接下来我们描述一下String的常用工具方法. /** * 为了精简的String结构,之前提到的方法省 ...
- Java源码赏析(六)Class<T> 类
目的 Class 类是每一个程序员都必须了解的,也是使用反射机制的基础. 这篇文章将Class 类的公共方法大致介绍了一遍(省略了安全.枚举.断言.注解相关代码). 代码 package java.l ...
- Mybatis源码解析(三) —— Mapper代理类的生成
Mybatis源码解析(三) -- Mapper代理类的生成 在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...
- Java源码赏析(四)Java常见注解
元注解 @Target :标识注解的目标,默认为所有 ElementType.TYPE(用于类) ElementType.FIELD(用于域,包括enum) ElementType.METHOD(用于 ...
- Java 源码赏析 - java.lang - Void
被人鄙视了,于是也来读读源码... package java.lang; /** * The Void class is an uninstantiable placeholder class to ...
- Java源码赏析(六)Java String 三顾
在大致了解了String之后,可能有的读者发现了,我们并没有谈到CharSequence接口. 原因是在这一节,CharSequence要和StringBuilder(Java1.5).StringB ...
- Java源码赏析(一)Object 类
写这个系列的原因,其实网上已经有无数源码分析的文章了,多一篇不多,少一篇不少,但为什么还要写这部分文章呢?于私,其一,上班族已经很久没有打过完整的一整段有意义的话,算是锻炼个人的书写.总结能力,其二, ...
- Java源码赏析(二)Java常见接口
一.Comparable接口 package java.lang; import java.util.*; public interface Comparable<T> { /** * i ...
- [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析
String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识, ...
随机推荐
- 瑞发科NS1081主控 + THGBM5G7A2JBAIR(eMMC) 制作16GB闪存驱动器
文档标识符:NS1081_FLASH-DRIVE_D-P9 作者:DLHC 最后修改日期:2020.8.22 本文链接:https://www.cnblogs.com/DLHC-TECH/p/NS10 ...
- pandas 数据表中的字符与日期数据的处理
前面我们有学习过有关字符串的处理和正在表达式,但那都是基于单个字符串或字符串列表的操作.下面将学习如何基于数据框操作字符型变量. 同时介绍一下如何从日期型变量中取出年份,月份,星期几等,如何计算两个日 ...
- latex:备忘代码
1.脚注代码: \footnote{欧几里德,约公元前330--340年.} 结果为: 2.改变某个字的字体形状,表示强调 \emph{勾股定理} 结果为(勾股数这三个字与其他字不一样): 3.正文中 ...
- Windows Server 2012 R2 时间同步
最近的项目两台服务器都是Windows Server 2012的系统,需要做时间同步,现在是一些从网上搜罗的步骤总结. 具体就是配置windows的注册表: 一.服务端配置 (NTP服务器,客户端将根 ...
- lynx浏览器使用教程
http://www.wocaoseo.com/thread-216-1-1.html LYNX浏览器是谷歌官方推荐的一款文本浏览器,主要用来模拟蜘蛛看到您页面时候的样子,谷歌在网站站长指南中提到: ...
- 力扣Leetcode 198. 打家劫舍
打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定 ...
- Android开发工具资料Android Manifest 权限描述大全 随时随地查询权限描述。
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985转载请说明出处. 在文章最后面赠送了markdown格式的此文章内容下载.(不要再问问什么用markdo ...
- 组件给App全局传值vue-bus的使用
npm安装 npm install vue-bus main.js引入 import VueBus from 'vue-bus' Vue.use(VueBus) 组件 getHouse(e){ thi ...
- vue问题整理
生命周期面试题 1.什么是 vue 生命周期 vue 实例从创建到销毁的过程就是生命周期. 也就是从开始创建.初始化数据.编译模板.挂在 dom -> 渲染.更新 -> 渲染.卸载等一系列 ...
- DVWA_sql injection(low)
这里主要记录下做题时的思路以及步骤,不查看源码也不对源码进行分析.(我这个dvwa是一个在线靶场,所以我也不确定是否与本地靶场有些许出入) 1.Low 将难度调为Low级别后,来到如下界面 首先输入一 ...