首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >关于String你还需要知道这些细节

关于String你还需要知道这些细节

作者头像
三好码农
发布于 2018-09-11 02:52:04
发布于 2018-09-11 02:52:04
34700
代码可运行
举报
运行总次数:0
代码可运行

关于String + 的故事

只要是写Java的,String肯定是经常用的,比如下面这样的代码(可能我们都写烂了)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String a = "Hello";
String b = "java";
String ab = a + b;

我们也一直都是这样写的,但是如果我们再进一步想一下就会发现问题,String在java中是一个类,java中是没有运算符重载的,那么二个String为什么可以直接用 + 号进行拼接呢?为了一探究竟,我们还是要看编译后的字节码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
L0
  LINENUMBER 18 L0
  LDC "Hello"
  ASTORE 1
L1
  LINENUMBER 19 L1
  LDC "java"
  ASTORE 2
L2
  LINENUMBER 20 L2
  NEW java/lang/StringBuilder
  DUP
  INVOKESPECIAL java/lang/StringBuilder.<init> ()V
  ALOAD 1
  INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
  ALOAD 2
  INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
  INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
  ASTORE 3

可以看到编译器new了一个 StringBuilder对象,然后调用了2次append方法进行字符串的拼接。也就是说+号拼接String 只是Java语言的语法糖而已,就跟上一篇说的自动装箱和拆箱一个意思。

测试一下编译器的智商

既然编译器会帮我们将String + 号拼接转化为StringBuilder拼接,那我们就用一段代码来测试一下它的智商到底怎么样。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String result = "";
for (int i = 0; i < 10; i++) {
   String a = "Hello";
   result += a;
}

同样很简单,我们来看字节码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
L0
  LINENUMBER 18 L0
  LDC ""
  ASTORE 1
L1
  LINENUMBER 19 L1
  ICONST_0
  ISTORE 2
L2
  FRAME APPEND [java/lang/String I]
  ILOAD 2
  BIPUSH 10
  IF_ICMPGE L3
L4
  LINENUMBER 20 L4
  LDC "Hello"
  ASTORE 3
L5
  LINENUMBER 21 L5
  NEW java/lang/StringBuilder
  DUP
  INVOKESPECIAL java/lang/StringBuilder.<init> ()V
  ALOAD 1
  INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
  ALOAD 3
  INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
  INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
  ASTORE 1
L6
  LINENUMBER 19 L6
  IINC 2 1
  GOTO L2

可以看到StringBuilder的创建是在循环体内创建的,所以会多次创建多个对象,效率很低,所以编译器没有那么智能,了解了这个,以后项目中需要循环拼接字符串时,避免直接使用+拼接。

字符串 + 还另有玄机

直接看下面的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final String a = "hello";
final String b = "world";
String result = a + b;

没看出来什么特别的!!!到底玄机在哪,直接看字节码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
L0
  LINENUMBER 19 L0
  LDC "hello"
  ASTORE 1
L1
  LINENUMBER 20 L1
  LDC "world"
  ASTORE 2
L2
  LINENUMBER 21 L2
  LDC "helloworld"
  ASTORE 3

额,编译器直接帮我们把a+b拼接了,因为a和b都是final类型的,在编译期值也是确定的,所以编译器帮我们做了这个优化。这一块的知识,就不展开的特别多的去分析了,目前我们得到的结论就是如果字符串拼接的双方都是 final 类型的常量字符串,编译器就会帮我们直接进行优化。

字符串常量池的故事

Java的设计者为了提高Java的运行效率,有很多精心的设计,字符串常量池就是其中之一(String Constant Pool),我们后面都简称为SCP。还是先看一段代码(面试题中经常见)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final String a = "hello";
final String b = "hello";
final String c = new String("hello");
final String d = c.intern();

System.out.println("a==b:" + (a == b));
System.out.println("a==c:" + (a == c));
System.out.println("a==d:" + (a == d));

运行结果如下:

  • a==b:true (a和b都存在于SCP中,所以它们是一个对象)
  • a==c:false (new的对象存在于堆中,所以c和a不是一个对象)
  • a==d:true (intern方法将字符串放入SCP中,并返回,所以a和d是一个对象)

SCP确实可以一定程度减少对象的重复创建,但是我们再想一种情形,如果我们改变了a字符串的值,我们肯定不希望b跟着变,但是a和b又指向同一个对象,很可能a 的修改会产生我们不愿意看到的结果。其实是没有问题的,因为Java中String是被设计成不可变的,如果要变就会重新生成一个新的对象,不会影响旧的对象,这也是SCP能够正常工作的前提。

SCP的前世今生

SCP在JDK6 之前是被设计在 永久代中的,并且不会进行垃圾回收,默认大小64M(可以通过-XX:MaxPermSize进行设置),所以如果在循环中,不断创建常量字符串放入SCP中,会导致OOM。JDK7开始,SCP被设计在堆中,这样它的大小限制被大大的放开了,而且会进行垃圾回收,Java也在不断的优化进步?。

最后:我自己的一点点小思考

为什么Java的设计者将String要被设计成immutable??? 我想可能有以下2个原因

  • 为了SCP的优化
  • 线程安全

设计没有完美的,有得必有失,immutable导致String的扩展被限制,所以Java提供了StringBuilder和StringBuffer二个类来帮助我们进行字符串操作。

以上

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.07.24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Python执行或远程执行shell命令
最近想要实现通过脚本循环再Linux下运行shell命令,经过探索发现使用Python语言有几种解决方案,在此简单记录。
宋天伦
2020/10/28
7.6K0
ubuntu1~16.04.9 下安装python3.6 详细教程(在腾讯云服务器上安装实例)
1.输入 sudo add-apt-repository ppa:jonathonf/python-3.6
用户2416682
2019/09/27
2.2K0
ubuntu1~16.04.9 下安装python3.6 详细教程(在腾讯云服务器上安装实例)
Install Rancher 1
因为整合了 k8s 的编排功能, 并且有着非常友好的操作界面,所以在目前的容器技术圈中有着很大的影响力
franket
2021/08/10
7130
为kubernetes(k8s)单独配置kubectl工具
Kubernetes API 是一个 HTTP REST API。这个 API 是真正的 Kubernetes 用户界面,通过它可以完全控制它。这意味着每个 Kubernetes 操作都作为 API 端点公开,并且可以通过对该端点的 HTTP 请求进行。因此,kubectl 的主要目的是向 Kubernetes API 发出 HTTP 请求:
小陈运维
2022/01/06
1.1K0
腾讯云Ubuntu Server 16.04.1 LTS升级系统到Ubuntu 18.04.1 LTS
* 此修改方案为临时方案(/etc/resolv.conf文件系统重启后会自动还原),最终方案待定,下方为腾讯云原装Ubuntu 18.04.1 LTS系统镜像 systemd-resolve --status执行结果,仅供参考。
用户1196360
2018/11/23
8.4K0
腾讯云Ubuntu Server 16.04.1 LTS升级系统到Ubuntu 18.04.1 LTS
WIN10下创建Ubuntu18.04子系统及安装图形界面
控制面板——>程序——>程序和功能——>启用或关闭Windows功能——>适用于Linux的Windows子系统——>确定 (然后重启)
好派笔记
2021/09/17
3.1K0
ansible基础使用
由于在生产中, 出于安全性考虑, 不使用ssh互信进行ansible通信, 可以在配置文件中通过键值对的方式定义变量, 注明用户名与密码
buiu
2021/11/25
4970
Python Paramiko实现sftp文件上传下载以及远程执行命令
Paramiko模块是基于Python实现的SSH远程安全连接,用于SSH远程执行命令、文件传输等功能。
py3study
2020/02/29
10.3K0
zzupdate:单条命令升级 Ubuntu 18.04 LTS
Ubuntu 18.04 版本已经发布,并得到各个社区的一致好评,因为 Ubuntu 18.04 可能是 Ubuntu 多年来最令人兴奋的版本。
用户8639654
2021/10/14
6610
【亲测有效】Ubuntu18.04 sudo apt update无法解析域名的解决方案
拿起了封尘已久的ThinkPad,输入 sudo apt update 的时候,发现这个命令变得不好使了,具体出现的问题如下图所示:
Angel_Kitty
2019/09/09
13.8K1
原来Python是这样连接远程主机的,你会吗?
在软件测试的过程中,涉及到远程Linux主机环境测试的时候,难免会遇到需要执行shell命令的场景,比如通过shell命令去配置一些环境或者去检查用例执行的结果等等,那么就是用到了比较常用的工具paramiko。
软测小生
2021/09/06
2.4K0
docker 操作进阶
sudo docker exec -it merlingpu env LANG=C.UTF-8 /bin/bash
AI拉呱
2021/01/14
5010
python利用paramiko连接远程服务器执行命令的方法
python中的paramiko模块是用来实现ssh连接到远程服务器上的库,在进行连接的时候,可以用来执行命令,也可以用来上传文件。
菲宇
2019/06/11
1.4K0
paramiko模块——ssh远程连接服务器并执行命令
https://www.cnblogs.com/ghylpb/p/12158061.html
GH
2020/03/19
3.3K0
如何搭建 nginx 静态网站
Nginx是一款面向性能设计的HTTP服务器,相较于Apache、lighttpd具有占有内存少,稳定性高等优势。Nginx不采用每客户机一线程的设计模型,而是充分使用异步逻辑从而削减了上下文调度开销,所以并发服务能力更强。整体采用模块化设计,有丰富的模块库和第三方模块库,配置灵活。 在Linux操作系统下,Nginx使用epoll事件模型,得益于此,Nginx在Linux操作系统下效率相当高。同时Nginx在OpenBSD或FreeBSD操作系统上采用类似于epoll的高效事件模型kqueue。
星空之下
2018/10/17
4.8K0
如何搭建 nginx 静态网站
终于来了,Percona发布XtraBackup for MySQL 8.0
Percona在9月12日,终于宣布第一个测试用的XtraBackup for MySQL 8.0版本给大家试用:
数据和云
2018/10/08
9820
终于来了,Percona发布XtraBackup for MySQL 8.0
python3 paramiko 远程执行 ssh 命令、上传文件、下载文件
在win10的系统下,本来想要python3直接调用ansible库进行远程执行的,但是很可惜,ansible是基于linux系统的ssh服务进行远程调用,不太兼容windows。 那么下面来使用paramiko库,直接手写一个ssh远程调用。
Devops海洋的渔夫
2019/06/15
6K0
python paramiko
近段时间用Python写一个小东西,每次修改代码后要手工上传到服务器,觉得很麻烦,虽然有WinSCP,找了一下资料,发现paramiko可以实现自动上传文件的功能,可惜的是,折腾了半天,在Python3.3下没有成功,最后退而求其次安装了2.7才弄好,记录如下:
py3study
2020/01/06
1.6K0
python paramiko模块简介
    paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接。
py3study
2020/01/09
1.2K0
TopDocs:一款美观实用的在线文档编辑系统,支持Markdown语法
说明:最近博主对文档程序小有需求,找了很久发现都是单页,而且还不支持移动端,不是很理想,所以萌JJ大雕就专门花了半天时间,给博主写了一个,该文档程序基于graphql、nuxtjs、mongodb、keystonejs的实时在线文档编辑系统,可用作各种在线文档编辑和展示,支持markdown语法,对移动端特别友好,这里就开源分享出来,给对文档有需求的人。
子润先生
2021/05/28
1.1K0
推荐阅读
相关推荐
Python执行或远程执行shell命令
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档