翻译人员: 铁锚
翻译日期: 2013年11月2日
原文链接: The substring() Method in JDK 6 and JDK 7 
 
在JDK6与JDK7这两个版本中,substring(int beginIndex, int endIndex)方法是不同的. 了解两个版本间的区别可以让你更好地使用它们. 为简单起见,本文中以 substring() 表示 substring(int beginIndex, int endIndex).

1. substring()功能简介
String对象的substring(int beginIndex, int endIndex)方法返回此对象的一个子串,从beginIndex 开始,一直到 endIndex-1 结束,共 (endIndex - beginIndex)个字符。
新手提示: 
    1.1 String 的索引和数组一样,都是从0开始.
    1.2 注意,方法名字是substring(),全小写.
    1.3 有个重载方法是substring(int beginIndex),从beginIndex索引处开始,取得子字符串.

String x = "abcdef";
int begin=1;
int end=3;
x = x.substring(begin, end);
System.out.println(x);

执行结果(包含索引为 begin,直到 end-1 的字符):

bc

2. 当substring()被调用时,发生了什么?
你应该知道,因为 x 是不可变的,当 指定 x 等于 x.substring(begin, end)时,实际上 x 指向了一个全新的字符串,如下图所示:

图1

然而,这幅图并不是完全正确的,堆内存中所真正发生的事也不是这么简单.那么,在JDK6和JDK7之间 substring()的调用到底有些什么区别呢?

3. JDK 6中的substring()方法
String实际上是一个字符数组.在 JDK6中, String对象主要包含3个属性域:

private final char value[];
private final int offset;
private final int count;

他们用于存储实际的字符数组,数组的第一个索引,以及String的字符个数.
当调用 substring() 方法时,创建了一个新的String对象,但是string的value[] 属性域仍然指向堆内存中的原来的那个数组。区别就是 两个对象的 count 和 offset 这两个值不同了。 如下图所示:

图2

要解释这个问题,下面是最关键部分的代码:

// JDK6,包级私有构造,共享 value数组提升速度
String(int offset, int count, char value[]) {this.value = value;this.offset = offset;this.count = count;
}public String substring(int beginIndex, int endIndex) {// ... 检查边界的代码// 如果范围和自己一模一样,则返回自身,否则用value字符数组构造一个新的对象return ((beginIndex == 0) && (endIndex == count)) ? this :new String(offset + beginIndex, endIndex - beginIndex, value);
}

4. JDK 6中substring()引起的问题
如果有一个" 非常"长的字符串,但每次使用substring()时只想要很小的一部分,那么将会引起另一个性能问题: 虽然你只需要很小的一部分,但是持有了整个value[]的引用,从而导致大量内存被占用。
要解决这个问题,在JDK6中可以让其指向一个真正的子字符串,示例代码:

x = x.substring(begin, end) + "";

5. JDK 7中的substring()方法
在JDK 7 中这个问题得到改进, substring()方法真实地在堆内存中创建了另一个字符数组.

图3
// JDK 7, 权限变为 public
public String(char value[], int offset, int count) {// ... 检查边界..// value 数组拷贝this.value = Arrays.copyOfRange(value, offset, offset+count);
}public String substring(int beginIndex, int endIndex) {// ... 检查边界..int subLen = endIndex - beginIndex;// 如果和自身一样,那就返回自身,否则返回构造的新对象return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);
}

参考:

1. Changes to substring

2. Java 6 vs Java 7 when implementation matters

相关阅读:

1. Top 10 questions about Java String.

2. Java method for spliting a camelcase string

3. Java: Convert File to Char Array

4. Count Number of Statements in a Java Method By Using Eclipse JDT ASTParser

JDK6和JDK7中String的substring()方法及其差异相关推荐

  1. JDK6和JDK7中的substring()方法

    2019独角兽企业重金招聘Python工程师标准>>> substring(int beginIndex, int endIndex)在JDK6与JDK7中的实现方式不一样,理解他们 ...

  2. c++中string的assign方法使用

    c++中string的assign方法使用 string的实际.h和.cpp文件是basic_string.h 和basic_string.tcc,所以string中assign也在这两个文件声明和定 ...

  3. JAVA中String的split方法

    我的个人网站: http://riun.xyz 以下源码版本:JDK1.8 简介 Java 中 String 的 split 方法可以将字符串根据指定的间隔进行切割,例如字符串 str = " ...

  4. Java中String类的方法及说明

    String : 字符串类型 一.构造函数      String(byte[ ] bytes):通过byte数组构造字符串对象.      String(char[ ] value):通过char数 ...

  5. 【转载】Java中String类的方法及说明

    转载自:http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html String : 字符串类型 一.构造函数      String ...

  6. String类substring方法

    踩了一个坑,记录一下String类的substring方法. substring方法可以用来截取字符串,它有两种表现形式: substring(int beginIndex) substring(in ...

  7. javascript中String的fromCharCode()方法

    前几天遇到一个bug,后端的模板引擎在输出形如: <div title="111 aaa">内容</div> 这样的内容时,无法输出' '空格,所以只能用' ...

  8. JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】

    文章目录 一.前言 二.图文理解String创建对象 1.例子一 2.例子二 3.例子三 4.例子四 5.例子五 6.例子六 三.深入理解intern()方法 1. 源码查看 2. 例子一 3. 例子 ...

  9. Java中String类 compareTo()方法比较字符串详解

    中心:String 是字符串,它的比较用compareTo方法,它从第一位开始比较, 如果遇到不同的字符,则马上返回这两个字符的ascii值差值.返回值是int类型 1.当两个比较的字符串是英文且长度 ...

  10. C库中没有itoa以及C++中string没有split方法的原因

    个人见解,欢迎讨论.这其实源于c/c++需要自己管理内存,而一个好的惯例是 自己申请的内存要自己释放掉 所以c/c++库函数一般都不会返回指针,你会说有些函数返回指针了呀,如 char *strcpy ...

最新文章

  1. request.getparameter特殊字符变成?号问号_15 个不可不知的 Linux 特殊字符,你懂几个?...
  2. 前端学习(2950):webpack目录结构
  3. Vasya and Multisets CodeForces - 1051C 模拟|分类讨论
  4. Qt工作笔记-使用QpropertyAnimation实现控件上下滑动的效果
  5. Android 驱动(15)---如何修改USB驱动能力
  6. java栈最小值的实现,关于java:算法图解如何找出栈中的最小值
  7. java海滩上有一_海滩上有一堆桃子,五只猴子来分-海滩上有一堆桃子,五只猴子来分java实现-吾爱编程网...
  8. linux中fork() 函数详解
  9. 牛客网项目——项目开发(十):热帖排行,生成长图,上传云服务器,性能优化
  10. unexpected error while obtaining UI hierarchy
  11. 将你的 Python 脚本转换为命令行程序
  12. 【无标题】【思特奇杯·云上蓝桥-算法集训营】第1周
  13. java 计算星座算法,java 依据生日计算星座
  14. 在MATLAB中创建函数
  15. sqlite expert 教程
  16. Drupal9自定义module添加多个定时任务
  17. 用python通过selenium自动化测试抓取天猫店铺数据
  18. [HDU1004] Let the balloon rise - 让气球升起来
  19. 性能测试工具Locust和JMeter比较
  20. 【智能CAN/串口转换器提供“透明转换、透明带标识转换和自定义协议转换”三种转换模式介绍、CAN转换器、CAN 485、CAN 232】

热门文章

  1. 在Ubuntu安装QT及相关环境配置
  2. 刷网课-踩坑——jsDOM获取不到页面元素节点-iframe标签获取元素节点
  3. 查纸张开数软件怎么样
  4. 客户管理系统代码项目_低代码案例:快速交付包含门店销售终端的SCM供应链管理系统...
  5. 通讯录系统课程设计——链表实现——c语言
  6. 树莓派4B改装RC玩具车玩转opencv系列教程(一)树莓派基础入门篇------Hello Raspberry Pi OS(Rasbian )!
  7. 物联网工程导论第二版答案选择题
  8. 队列(纯C语言实现)
  9. 华硕重装系统键盘灯失效 =重装ATK驱动
  10. 如何将html转换成url,HTML URL