学习JDK源码(一):String
用了好久的Java了,从来没有看过jdk的源码,趁着今天有点时间,拿出了jdk的源码看了下,今天先看了关于String的,毕竟开发中String类型使用最广泛。在我们下载安装jdk的时候,部分源码也已经同时存放在我们电脑里了,具体路径为jdk目录下的src.zip压缩包,解压即可。
java.lang.String
1 public final class String 2 implements java.io.Serializable, Comparable<String>, CharSequence
这是String类的声明,很明显它是由final类型声明的,所以它不能被继承,而它又实现了Serializable接口,代表它是可以被序列化的。
接着我们来看看类内部是怎么定义的
/** The value is used for character storage. */private final char value[];
使用final类型的字符数组存储字符串内容,String初始化后就不能被改变。
有一种写法,String s = “abc”; s = “bcd”;当然这并不是改变了字符串s的值,只是将s指向了一个新的字符串,所以千万不要以为字符串是可以变的。
/** Cache the hash code for the string */private int hash; // Default to 0
指定缓存字符串的hash code的值,默认为0
/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;
相当于java类的身份证。主要用于版本控制。serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。有两种生成方式: 一个是默认的1L,比如:private static final long serialVersionUID = 1L; 一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如: private static final long serialVersionUID = xxxxL;
/*** Class String is special cased within the Serialization Stream Protocol.** A String instance is written into an ObjectOutputStream according to* <a href="{@docRoot}/../platform/serialization/spec/output.html">* Object Serialization Specification, Section 6.2, "Stream Elements"</a>*/private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];
serialPersistentFields 用于指定哪些字段需要被默认序列化,如:
private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("name", String.class), new ObjectStreamField("a", Integer.TYPE) };
看了String类的构造方法,惊叹不已,源码中有足足15种构造方法,其中最常用的不外乎以下几种
public String(byte bytes[]) {this(bytes, 0, bytes.length);} public String(StringBuffer buffer) {synchronized(buffer) {this.value = Arrays.copyOf(buffer.getValue(), buffer.length());}} public String(StringBuilder builder) {this.value = Arrays.copyOf(builder.getValue(), builder.length());}
再往后看就是String类自身提供的一系列方法了:
// 返回字符串的长度 public int length() {return value.length;}// 字符串是否为空public boolean isEmpty() {return value.length == 0;}// 字符串目标位置的字符public char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];}// 返回指定索引处的字符public int codePointAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return Character.codePointAtImpl(value, index, value.length);}// 返回指定索引之前的字符public int codePointBefore(int index) {int i = index - 1;if ((i < 0) || (i >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return Character.codePointBeforeImpl(value, index, 0);}// 返回此 String 的指定文本范围中的 Unicode 代码点数public int codePointCount(int beginIndex, int endIndex) {if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {throw new IndexOutOfBoundsException();}return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);} //返回从0处开始的第i个Code Point的位置 public int offsetByCodePoints(int index, int codePointOffset) {if (index < 0 || index > value.length) {throw new IndexOutOfBoundsException();}return Character.offsetByCodePointsImpl(value, 0, value.length,index, codePointOffset);}//判断两个字符串是否相等 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;}//不区分大小写的情况下比较两个字符串是否相等 public boolean equalsIgnoreCase(String anotherString) {return (this == anotherString) ? true: (anotherString != null)&& (anotherString.value.length == value.length)&& regionMatches(true, 0, anotherString, 0, value.length);} //计算当前字符串比目标字符串长度大多少 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;}
//获取哈希值 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;} //返回某个指定的字符串值在字符串中首次出现的位置 public int indexOf(int ch) {return indexOf(ch, 0);} public int indexOf(int ch, int fromIndex) {final int max = value.length;if (fromIndex < 0) {fromIndex = 0;} else if (fromIndex >= max) {// Note: fromIndex might be near -1>>>1.return -1;}if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {// handle most cases here (ch is a BMP code point or a// negative value (invalid code point))final char[] value = this.value;for (int i = fromIndex; i < max; i++) {if (value[i] == ch) {return i;}}return -1;} else {return indexOfSupplementary(ch, fromIndex);}} //返回某个指定的字符串值在字符串中最后一次出现的位置 public int lastIndexOf(int ch) {return lastIndexOf(ch, value.length - 1);} public int lastIndexOf(int ch, int fromIndex) {if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {// handle most cases here (ch is a BMP code point or a// negative value (invalid code point))final char[] value = this.value;int i = Math.min(fromIndex, value.length - 1);for (; i >= 0; i--) {if (value[i] == ch) {return i;}}return -1;} else {return lastIndexOfSupplementary(ch, fromIndex);}} //从指定位置截取字符串直至最后一位 public String substring(int beginIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}int subLen = value.length - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);} //截取字符串从beginIndex至beginIndex 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 String concat(String str) {int otherLen = str.length();if (otherLen == 0) {return this;}int len = value.length;char buf[] = Arrays.copyOf(value, len + otherLen);str.getChars(buf, len);return new String(buf, true);} //字符串替换 public String replace(char oldChar, char newChar) {if (oldChar != newChar) {int len = value.length;int i = -1;char[] val = value; /* avoid getfield opcode */while (++i < len) {if (val[i] == oldChar) {break;}}if (i < len) {char buf[] = new char[len];for (int j = 0; j < i; j++) {buf[j] = val[j];}while (i < len) {char c = val[i];buf[i] = (c == oldChar) ? newChar : c;i++;}return new String(buf, true);}}return this;} //判断字符串是否包含在另一个字符串中 public boolean contains(CharSequence s) {return indexOf(s.toString()) > -1;} //将目标字符串中匹配的字符全部替换成另一字符串 public String replaceAll(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceAll(replacement);} //按约定分隔符将目标字符串分割成多个字符串并返回字符串数组 public String[] split(String regex, int limit) {/* fastpath if the regex is a(1)one-char String and this character is not one of theRegEx's meta characters ".$|()[{^?*+\\", or(2)two-char String and the first char is the backslash andthe second is not the ascii digit or ascii letter.*/char ch = 0;if (((regex.value.length == 1 &&".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||(regex.length() == 2 &®ex.charAt(0) == '\\' &&(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0)) &&(ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE)){int off = 0;int next = 0;boolean limited = limit > 0;ArrayList<String> list = new ArrayList<>();while ((next = indexOf(ch, off)) != -1) {if (!limited || list.size() < limit - 1) {list.add(substring(off, next));off = next + 1;} else { // last one//assert (list.size() == limit - 1); list.add(substring(off, value.length));off = value.length;break;}}// If no match was found, return thisif (off == 0)return new String[]{this};// Add remaining segmentif (!limited || list.size() < limit)list.add(substring(off, value.length));// Construct resultint resultSize = list.size();if (limit == 0) {while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {resultSize--;}}String[] result = new String[resultSize];return list.subList(0, resultSize).toArray(result);}return Pattern.compile(regex).split(this, limit);}
转载于:https://www.cnblogs.com/timePasser-leoli/p/7873311.html
学习JDK源码(一):String相关推荐
- JDK源码阅读 String
1.String是如何做到不可变?为什么要将它设计为不可变类? 答:首先String类是被final修饰,不能被继承:它把数据存放在一个数组value中,value同样被final修饰:所 ...
- 死磕JDK源码之String
String本质是对char数组的封装 Serializable接口 实现Serializable接口的类可以被序列化 Comparable接口 实现Comparable接口的类可以支持排序,需要重写 ...
- [置顶] 学习JDK源码:可进一步优化的代码
1.参数化类型的构造函数比较啰嗦 new HashMap<String, List<String>>() 如果你调用参数化类的构造函数,那么很不幸,你必须要指定类型参数,即便上 ...
- JDK源码学习笔记——String
1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() {i ...
- 非常实用,IDEA 搭建JDK源码学习环境(可修改+断点+笔记)
点击关注公众号,实用技术文章及时了解 来源:chenxiao.blog.csdn.net/article/details/104369824 在学习JDK源码的时候,自然少不了代码的调试. 阅读与调试 ...
- 简单工厂 jdk源码解析
我们看一下简单工厂在JDK源码的一些体现,我们看一个比较熟悉的类,Calendar这么一个类,我们找一个getInstance这么一个方法,public static Calendar getInst ...
- 如何更高效地阅读JDK源码
简介 阅读源码的几个问题: 为什么要看JDK源码 JDK源码的阅读顺序 JDK源码的阅读方法 为什么要看JDK源码 一,JDK源码是其它所有源码的基础,看懂了JDK源码再看其它的源码会达到事半功倍的效 ...
- JDK源码学习笔记——Integer
一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...
- JDK源码学习-基础
JDK源码学习 目录 基础 1. 安装 1.1 下载JDK 1.2 配置环境变量 1.3 验证 2. 简单的程序 2.1 编写代码 2.2 编译文件 2.3 执行类 3. java基本类型 基础 1. ...
最新文章
- Redis 官方可视化工具,功能强大、干净又卫生!
- 【ZJ选讲·字符串折叠】
- Vue电商后台B站的项目需要的材料 密码等
- python才能做爬虫,No,C#也可以!
- 从jsp向servlet传送数据的两种方式
- bash: ssh: command not found解决方法
- 计算机监控网络运维合同书,网络服务托管运维合同范本
- win10 UWP RSS阅读器
- 服务器怎么识别swf文件,服务器架设swf支持播放flv格式 swf格式
- c语言中power是什么变量,c语言学习新手必看 power by vcok.com[转载]
- 海康直连工具 海康测试工具,工程宝测试软件等
- 必须收藏!这13个优秀React JS框架,没用过就很离谱!
- 直播已入下半场,秀场直播该何去何从?
- 改进神经网络的学习方法(上)
- 「开源学」:如何分门别类理解开源
- qt4.8 利用串口实现智能大棚系统
- 如何让soso百科通过
- MSI Afterburner(微星显卡超频工具)v4.6.0 中文版
- 华为mate30epro是鸿蒙系统吗,华为mate30epro和mate30区别 华为mate30epro和mate30区别在哪 - 云骑士一键重装系统...
- 赚钱思考:屌丝逆袭应该怎么开始?
热门文章
- 明小子动力上传拿webshell(1).zip
- [转]:tbox中数据库的使用
- Codeforces Round #350 (Div. 2) B. Game of Robots 水题
- maven中net.sf.json报错的解决方法
- 谢宝友:会说话的Linux内核
- Linux基本管理篇
- 进程在linux系统中原理,Linux系统原理知识 进程切换的概念介绍
- python3爬虫入门实例_10个python爬虫入门实例(小结)
- mysql 2100,MySQL 实现准实时的表级别DML计数
- 数据库封装 sql server mysql_mysql操作数据库进行封装实现增删改查功能