@

你真的了解String吗?之前一篇博客写jvm时,就觉得String可以单独拎出来写一篇博客,毕竟几乎所有的面试都是以String开始的,由此可以延伸出线程安全问题,jvm内存模型等问题。也以此告诫我们,作为一个技术开发人员,时刻需要关注底层的实现,保持刨根问底的好奇心的重要性!

这里提一下解读源码的思路:1.看其实现、继承->2.看其构造方法->3.看其重写的方法->4.了解其其他方法的实现

源码实现

1.以主流的jdk1.8来说,Spring 内部实际存储的结构为char数组,源码如下:

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
//...其他内容省略
}

构造方法

我们先来看看它重要的4个构造方法:

// String 为参数的构造方法
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
// char[] 为参数的构造方法
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
// StringBuffer 为参数的构造方法
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
// StringBuilder 为参数的构造方法
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

可以看到除了String 为参数的构造方法是直接赋值,其他三个方法都是调用Arrays.copyOf()方法复制一份等长的数据,并且StringBuffer考虑到线程安全的问题,使用了synchronized关键字。

Arrays.copyOf()实际上是调用了底层的实现(native本地方法,实际调用了C的方法库,对内存进行读写操作):System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));

equals

String 重写了equals() 方法,源码如下:

/* @see  #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) { // 对象引用相同直接返回true
return true;
}
if (anObject instanceof String) { // 判断值是否为String类型
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
// 把两个值都转为char[] 数组对比
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
// 循环比对两个字符串的每一个字符
while (n-- != 0) {
// 如果有一个字符不相同就返回false
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

还有一个和equals()比较类似的方法equalsIgnoreCase(),用于忽略字符串大小写后进行字符串比对!

compareTo()方法,用于比较两个字符串,返回int类型,源码:

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) {
// 有字符不相等就返回差值(隐式转换 a为1 z为26)
return c1 - c2;
}
k++;
}
return len1 - len2;
}

从源码可以看出,compareTo方法会循环对比所有的字符,当连个字符串中有任意一个字符串不相同时,就返回差值。当相等时返回0;(注:equals 和 compareTo只比较字符层面是否相等,不比较对象的引用是否一致)

例如下代码:

String str1 = "java";
String str2 = "java";
String str3 = new String("java");
String str4 = new String("java"); System.out.println(str1==str2); // true
System.out.println(str1.equals(str2)); // true
System.out.println(str1.compareTo(str2)); // 0 System.out.println(str2==str3); // false
System.out.println(str2.equals(str3)); // true
System.out.println(str2.compareTo(str3)); // 0 System.out.println(str3==str4); //false
System.out.println(str3.equals(str4)); // true
System.out.println(str3.compareTo(str4)); // 0

可以看出,equals() 和 compareTo() 方法是等价的,唯一的不同是equals(Object),compareTo(String) 参数不同!

其他方法

  • indexOf() 查询字符串首次出现的下标位置
  • lastIndexOf() 查询字符串最后出现的下标位置
  • contain() 查询字符串是否包含另一个字符串
  • toLowerCase() 把字符串全部转为小写
  • toUpperCase() 把字符串全部转换为大写
  • length() 查询字符串长度 (数组查看长度size(),但是前台数组查看长度依然是length(),有时候前端写忘记了关键还不报错!)
  • trim() 去掉首位空格
  • replace() 替换字符串中某些字符
  • split() 把字符串分割并返回字符串数组
  • join() 把字符串数组转换为字符串

常见面试题

1.为什么String 要有final修饰?

2.String中StringBuilder 和StringBuffer 有什么区别?

3.String 的intern() 方法有什么含义?

4.String 类型在jvm 中是如何存储的?编译器对String 做了哪些优化?

接下来我们一个个看下这些问题的答案:

1.为了安全和高效的考虑,如果不是final的话,传参和内部指令调用时,它的值被改变了的话可能会引起不可预知的系统崩溃问题,且传参的时候需要重新拷贝一个新值,性能上会有一定损失!

2.StringBuilder 是非线程安全的,StringBuffer是线程安全的,但是考虑了线程安全就兼顾不了性能,在非并发的操作下我们选择StringBuilder来操作字符串的拼接。

3.intern() 方法是将字符串保存到常量池中。

String s1 = "java";
String s2 = s1.intern();
String s3 = new String("java");
String s4 = s3.intern(); System.out.println(s1 == s2); // true
System.out.println(s1 == s3); //false
System.out.println(s3 == s4);// false s3在堆中 s4在常量池中

4.编译器堆代码进行了优化如下:

String s1 = "ja" + "va";
String s2 = "java";
System.out.println(s1 == s2);//true

其中"ja" + "va"被直接编译成了"java".因此s1==s2才成立!

小结:String的面试点基本就在== equals()和StringBuild和StringBuffer这里!还有要问就会问jvm 线程并发了。还是要多看源码,知其然知其所以然!

从String 聊源码解读的更多相关文章

  1. java.lang.String 类源码解读

    String类定义实现了java.io.Serializable, Comparable<String>, CharSequence 三个接口:并且为final修饰. public fin ...

  2. String、StringBuffer、StringBuilder源码解读

    序 好长时间没有认真写博客了,过去的一年挺忙的.负责过数据库.线上运维环境.写代码.Code review等等东西挺多. 学习了不少多方面的东西,不过还是需要回归实际.加强内功,方能扛鼎. 去年学习M ...

  3. Flask(4)- flask请求上下文源码解读、http聊天室单聊/群聊(基于gevent-websocket)

    一.flask请求上下文源码解读 通过上篇源码分析,我们知道了有请求发来的时候就执行了app(Flask的实例化对象)的__call__方法,而__call__方法返回了app的wsgi_app(en ...

  4. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  5. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  6. AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking

    AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...

  7. AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization

    这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...

  8. YYModel 源码解读(二)之NSObject+YYModel.h (1)

    本篇文章主要介绍 _YYModelPropertyMeta 前边的内容 首先先解释一下前边的辅助函数和枚举变量,在写一个功能的时候,这些辅助的东西可能不是一开始就能想出来的,应该是在后续的编码过程中 ...

  9. AFNetworking 3.0 源码解读 总结

    终于写完了 AFNetworking 的源码解读.这一过程耗时数天.当我回过头又重头到尾的读了一篇,又有所收获.不禁让我想起了当初上学时的种种情景.我们应该对知识进行反复的记忆和理解.下边是我总结的 ...

随机推荐

  1. win10 安装虚拟机提示 主IP地址显示网络信息不可用

    问题:在虚拟机详情下面显示 主ip地址:网络信息不可用 解决办法: 先root用户[root@dfhf~]#cd ..[root@dfhf/]#cd /etc/sysconfig/network-sc ...

  2. 使用MySql对IdentityServer4进行持久化

    哈喽大家好,看见网上很少有使用MySql进行持久化的,毕竟又很多坑,说句实话,就连 MySql.Data.EntityFrameworkCore 都有问题,不知道是.net core更新太快还是其它的 ...

  3. What is the difference between shades and shadows?

    Shade is the darkness of an object not in direct light, while shadows are the silhouette of an objec ...

  4. Requests发送带cookies请求

    一.缘 起 最近学习[悠悠课堂]的接口自动化教程,文中提到Requests发送带cookies请求的方法,笔者随之也将其用于手头实际项目中,大致如下 二.背 景 实际需求是监控平台侧下发消息有无异常, ...

  5. Mybatis---在控制台打印sql语句

    在mybatis主配置文件中mybatis.xml的<configuration>标签中加入 <settings> <setting name="logImpl ...

  6. hibernate连接oracle

    <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC           & ...

  7. Reverse Subarray To Maximize Array Value

    2020-02-03 20:43:46 问题描述: 问题求解: public boolean canTransform(String start, String end) { int n = star ...

  8. Filebeat快速入门

    Filebeat快速入门 本笔记整理于https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html ...

  9. 蓝桥杯——一步之遥,扩展gcd的应用

    1. 一步之遥 [问题描述]从昏迷中醒来,小明发现自己被关在X星球的废矿车里.矿车停在平直的废弃的轨道上.他的面前是两个按钮,分别写着“F”和“B”. 小明突然记起来,这两个按钮可以控制矿车在轨道上前 ...

  10. 「MoreThanJava」当大学选择了计算机之后应该知道的

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...