热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java源码学习java.lang.String

java.lang.String是使用频率非常高的类。要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的。由java.lang.String,自然联想

java.lang.String是使用频率非常高的类。要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的。由java.lang.String,自然联想到java.lang.StringBuffer和java.lang.StringBuilder,下篇文章再来研究java.lang.StringBuffer和java.lang.StringBuilder。


重要属性

java.lang.String对象中字符串主要是以字符数组的形式存储。当调用对象方法获取字符串长度时,直接返回数组长度。判断字符串是否为空isEmpty()时,也直接检查数组长度是否为0。其部分发生代码如下所示:

/** The value is used for character storage. */

private final char value[];
/** Cache the hash code for the string */

private int hash; // Default to 0

value:存储字符串的字符数组。该数组为final变量,一旦赋值,将不会更改。

hash:该String对象的哈希值。


构造方法

java.lang.String对象构造方法比较多,列举如下:

public String()

public String(String original)

public String(char value[])

public String(char value[], int offset, int count)

public String(int[] codePoints, int offset, int count)

@Deprecated

public String(byte ascii[], int hibyte, int offset, int count)

@Deprecated

public String(byte ascii[], int hibyte)

public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException

public String(byte bytes[], int offset, int length, Charset charset)

public String(byte bytes[], String charsetName) throws UnsupportedEncodingException

public String(byte bytes[], Charset charset)

public String(byte bytes[], int offset, int length)

public String(byte bytes[])

public String(StringBuffer buffer)

public String(StringBuilder builder)

在 public String(StringBuffer buffer) 中,传入形参为StringBuffer,StringBuffer为线程安全类。则在此构造方法内部进行了synchronized关键字锁同步。代码如下:

public String(StringBuffer buffer) {

synchronized(buffer) {

this.value = Arrays.copyOf(buffer.getValue(), buffer.length());

}

}

在 public String(StringBuilder builder) 中,传入形参为StringBuilder,StringBuilder为非线程安全类。则在此构造方法内部内部未做同步处理,对比 public String(StringBuffer buffer) 。代码如下:

public String(StringBuilder builder) {

this.value = Arrays.copyOf(builder.getValue(), builder.length());

}
常用方法

java.lang.String对象中封装方法非常多,仅针对常用方法源代码进行分析。如:equals(),replace(), indexOf(),startsWith(),compareTo(),regionMathes(),hashCode()。


public boolean equals(Object anObject)

用于比较两对象存储内容是否相同。采用比较巧妙的方式进行排除比较:(1)先“==”比较两对象是否是同一对象,若是,直接返回true, 否则进一步判断;(2)判断待比较对象类型是否是java.lang.String,若不是,直接返回false,否则进一步判断;(3)判断两字符串长度是否相等,若不是直接返回false,否则进一步判断;(4)从字符数组中第一个字符开始,依次进行比较,一旦发现不相同字符直接返回false,若所在字符均相同则返回true。对字符数组中字符依次进行比较是一件非常耗时的操作,将此操作放在最后执行,先利用其它条件进行对其进行判断。比较巧妙!

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 String replace(char oldChar, char newChar)

将字符串中指定字符替换为新的字符。(1)先判断待替换字符和新字符是否相同,若相同,则直接返回原字符串,若不同,则继续执行;(2)找出第一次出现待替换字符位置i,创建新的等长字符数组,将该位置之前的字符依次放入新的字符数组中;(3)从位置i处依次遍历比较原字符数组中字符是否是待替换字符,若是,则将新字符放入新字符数组对应位置,若不是,则将原字符数组中字符放入对应位置。巧妙做了一个小优化,直接找出第一次出现待替换字符的位置,再从此处开始遍历,提高效率。

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
if (val[i] == oldChar) {

break;

}

}

if (i
char buf[] = new char[len];

for (int j = 0; j
buf[j] = val[j];

}

while (i
char c = val[i];

buf[i] = (c == oldChar) ? newChar : c;

i++;

}

return new String(buf, true);

}

}

return this;

}

public String replace(CharSequence target, CharSequence replacement)

该方法是我们通常意义所用到的 public String replace(String target, String replacement) ,java.lang.String实现了java.lang.CharSequence接口。方法内部调用正则表达式匹配替换来实现。

public String replace(CharSequence target, CharSequence replacement) {

return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(

this).replaceAll(Matcher.quoteReplacement(replacement.toString()));

}

public int indexOf(String str)

该方法是找出目标字符串是第一次出现指定子字符串的位置,若不存在,则返回-1,若存在,则返回位置坐标。具体实现是调用 static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) 方法。先对目标字符串中出现子字符串的位置可能范围,然后在此范围中遍历找出与子字符串第一个字符相同的位置,并对后面字符进行比较分析。

/**

* Returns the index within this string of the first occurrence of the

* specified substring.

*/

public int indexOf(String str) {

return indexOf(str, 0);

}
/**

* Returns the index within this string of the first occurrence of the

* specified substring, starting at the specified index.

*/

public int indexOf(String str, int fromIndex) {

return indexOf(value, 0, value.length,

str.value, 0, str.value.length, fromIndex);

}
/**

* Code shared by String and StringBuffer to do searches. The

* source is the character array being searched, and the target

* is the string being searched for.

*

* @param source the characters being searched.

* @param sourceOffset offset of the source string.

* @param sourceCount count of the source string.

* @param target the characters being searched for.

* @param targetOffset offset of the target string.

* @param targetCount count of the target string.

* @param fromIndex the index to begin searching from.

*/

static int indexOf(char[] source, int sourceOffset, int sourceCount,

char[] target, int targetOffset, int targetCount,

int fromIndex) {

if (fromIndex >= sourceCount) {

return (targetCount == 0 ? sourceCount : -1);

}

if (fromIndex <0) {

fromIndex = 0;

}

if (targetCount == 0) {

return fromIndex;

}
char first = target[targetOffset];

int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {

/* Look for first character. */

if (source[i] != first) {

while (++i <= max && source[i] != first);

}
/* Found first character, now look at the rest of v2 */

if (i <= max) {

int j = i + 1;

int end = j + targetCount - 1;

for (int k = targetOffset + 1; j
== target[k]; j++, k++);
if (j == end) {

/* Found whole string. */

return i - sourceOffset;

}

}

}

return -1;

}

public int compareTo(String anotherString)

该方法是对字符串集合进行排序的基础,通过此方法可比较两字符串大小,原理很简单,源代码如下:

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
char c1 = v1[k];

char c2 = v2[k];

if (c1 != c2) {

return c1 - c2;

}

k++;

}

return len1 - len2;

}

public boolean startsWith(String prefix)

判断目标字符串是否以指定字符子串开关,该方法内部是调用 public boolean startsWith(String prefix, int toffset) 方法实现,原理很简单,代码如下:

/**

* Tests if this string starts with the specified prefix.

*

* @param prefix the prefix.

*/

public boolean startsWith(String prefix) {

return startsWith(prefix, 0);

}

public int hashCode()

其hashCode()代码如下:

public int hashCode() {

int h = hash;

if (h == 0 && value.length > 0) {

char val[] = value;
for (int i = 0; i
h = 31 * h + val[i];

}

hash = h;

}

return h;

}

Java源码学习 -- java.lang.String的相关教程结束。



推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
author-avatar
缪宇驰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有