(史上最白话最简单)深度剖析Java的split();方法(附:怎么能看懂JDK源码?)

本文主要是介绍(史上最白话最简单)深度剖析Java的split();方法(附:怎么能看懂JDK源码?),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

随着Java学习的深入,我们不仅仅会要求自己熟练使用一些API的方法,更想看看这些方法的底层是如何实现的,然而你如果想进步那么必须要训练看源码的能力,将来学高级框架的时候是一定会看底层源码的,所以必须要从相对基础的JDK源码训练开始!

ヾ(◍°∇°◍)ノ゙



目录

前言:

什么是split方法?(理解的可以跳过)

第一个:split(String regex)  翻译-->拆分围绕给定正则表达式匹配项的这个字符串。

第二个:split(String regex, int limit) 翻译-->拆分围绕给定正则表达式匹配项的这个字符串。

split底层如何实现的?(重头戏来了)

总结


什么是split方法?(理解的可以跳过)

直接上API!

可以看到他是java.lang.String包下的一个方法,重载方法共有两个,一个一个说:


第一个:split(String regex)  翻译-->拆分围绕给定正则表达式匹配项的这个字符串。

什么意思呢?就是你传递的参数是啥,我就以它为分隔符,分割你的字符串,如果还不明白请看下面的例子:

public class SplitTest {public static void main(String[] args) {String s = "小bean哥,是,帅哥";String[] res = s.split(",");//regex = ","也就是说,作为分隔符System.out.println(Arrays.toString(res)+"\n"+"字符串共有:"+res.length+"个");}
}
//输出结果
//[小bean哥, 是, 帅哥]
//字符串共有:3个

第二个:split(String regex, int limit) 翻译-->拆分围绕给定正则表达式匹配项的这个字符串。

那么问题来了,这个limit干啥用的?直接查API,结果如下:

Tips:ψ(*`ー´)ψ尽量还是训练自己看英文文档的能力!!!!really essential.

引自:http://tool.oschina.net/apidocs/apidoc?api=jdk_7u4

其大致意思是说:limit是会限制数组大小的一个因子,当limit>0,则最多应用n-1次模式,数组的长度将不大于n,并且数组的最后一个条目将包含最后匹配分隔符之外的所有输入。limit=0,数组可能为任意长度,数组最后的空字符串将会被抛弃(这个一会看了源码大家就知道了,先不说,卖个关子),当limit<0的时候,数组可以包含任意长度的字符串,不删除最后一个空字符。

话不多说,直接上例子:

public class SplitTest {public static void main(String[] args) {String s = "小bean哥,是,帅哥,";String[] res = s.split(",",-1);int i = 1;for (String ss:res) {System.out.println("第"+i+"个字符串为["+ss+"]");i++;}System.out.println("字符串共有:"+res.length+"个");}
}
//输出结果:
/**第1个字符串为[小bean哥]第2个字符串为[是]第3个字符串为[帅哥]第4个字符串为[]字符串共有:4个*/

只给大家举两个例子,剩下的感兴趣的同学可以自己尝试一下:

上图是limit为-1的时候,会保留所有的分割后的字符串;

再给大家看一个limit为0(默认值)的例子:

public class SplitTest {public static void main(String[] args) {String s = "小bean哥,是,帅哥,";String[] res = s.split(",",0);int i = 1;for (String ss:res) {System.out.println("第"+i+"个字符串为["+ss+"]");i++;}System.out.println("字符串共有:"+res.length+"个");}
}
//输出结果:
/**第1个字符串为[小bean哥]第2个字符串为[是]第3个字符串为[帅哥]字符串共有:3个*/

为啥成了三个字符串呢?上面其实已经说过了,当limit为0的时候,会自动清空最后一个空值!!!很重要!!

split底层如何实现的?(重头戏来了)

鼠标左键加ctrl进入源码:

以下就是源码部分了,其实也并不多,我们仔细的看完介绍文档后,大致在头脑中应该清楚的东西有:

1、split有两个方法

2、regex是分隔符

3、limit是以上所说的

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;//这个ch其实就是你输入regex对应的ASCII码所对应的的值//不要怕烦,耐心看完!~if (((regex.value.length == 1 &&//你的分隔符长度是否为1".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||//是不是{.$|()[{^?*+\\}这些符号,并且把对应ascii的值赋给ch(regex.length() == 2 &&//分隔符是否长度为2regex.charAt(0) == '\\' &&//是不是形如\t \\第一个字符为反斜杠这样的(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&//是不是第二个字符为数字之前的所有字符,字符编码小于48的字符,大家不懂得话可以查一下ASCII码表--https://baike.baidu.com/item/ASCII/309296?fr=aladdin((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0)) && //这是判断是不是分隔符为字母(ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE)) //是不是编码中的 Unicode 低代理项代码单元的最大值到最小值的范围{int off = 0;//分割的起点int next = 0;//下一个出现分隔符的位置boolean limited = limit > 0;//看看你的limit是不是为正数ArrayList<String> list = new ArrayList<>();//生成一个新数组装分割好了的数据while ((next = indexOf(ch, off)) != -1) {//只要还有下一个分隔符,就继续执行if (!limited || list.size() < limit - 1) {//如果limit不是大于0的数,或者还没还没装满字符串到数组中list.add(substring(off, next));//添加分割的起点到第一个分隔符的字符串到listoff = next + 1;//分割起点为上一次出现分隔符的后一个位置} else {    // 到头了//assert (list.size() == limit - 1);list.add(substring(off, value.length));//把最后的字符串收容到list当中off = value.length;//维护off的位置,将指针移到最后一位break;}}// 分隔符没匹配到,直接把这个字符返回了if (off == 0)return new String[]{this};// 添加剩余段if (!limited || list.size() < limit)list.add(substring(off, value.length));// 生成结果int 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);}

如果还是看不懂的话,就看我下面的例子

字符串对应数组的位置为:

共计:7个字符串。

然后系统查找regex对应的逗号是否在ASCII中

显然逗号属于,然后先找第一个逗号所在位置,很明显是小bean哥后面,所以是第一位,因此next = 1; off作为起始位置,初始值为0

通过调用 list.add(substring(off, next)); off = next + 1;就把第0位到第一位的字符串保存到了list中了,也就是把"小bean哥"保存到ArrayList中了!维护一下off,新的值为第一次出现逗号位置的下一位,也就是第二位,next为第二个逗号出现的位置,也就是第3位,然后再调用 list.add(substring(off, next)); off = next + 1;把“是”保存到ArrayList中,所以按照这个步骤,把“小bean哥”、“是”、“帅哥”、“”保存到了list中。

int resultSize = list.size();if (limit == 0) {while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {resultSize--;}}

接下来如果limit=0,则把list里面的4个值检查一下,最后的值是否为空,显然我这个例子第4位是“ ”,所以要把resultSize自减。

String[] result = new String[resultSize];

然后创建一个以resultSize(这个例子为3)为容量的字符串数组,剩下的无非就是给数组传值的过程,split方法大致到这里就结束了~

总结

读别人代码本身就是痛苦的事情,不怕烦才能看懂!

本篇博客到这里差不多就结束了,为了读懂原生代码,我大致总结了以下的方法,大家可以作为参考:

1、先查API文档,尽量看英文文档,中文API差不多都是谷歌机翻,所以多少会跟作者本意有所偏差,我知道这是一个艰辛的开始,在初期你会消耗大量的时间进行查单词,但是这一切都是值得的!

2、搞清楚方法中每一个参数的含义和作用,弄清楚返回值返回的是什么,这个很重要!

3、不用debug到代码的最深处,你不需要一直跟debug到代码的最深处,虽然这才是真正的刨根问底,但是对于新手来说这样会让你更糊涂,还有一个小技巧,如果你使用ctrl+鼠标左键跟进了代码,那么使用Ctrl+Alt+<或者Ctrl+Alt+>可以快速回到上次或下次光标出现的所在行

4、在IDEA中使用Ctrl+Q可以快速查看注解!(Eclipse用户请参考这里~)

ヾ(@^▽^@)ノ欢迎大佬指正,欢迎小白学习!

这篇关于(史上最白话最简单)深度剖析Java的split();方法(附:怎么能看懂JDK源码?)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1062827

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程