java字符串拼接例子_Java详解【String】+【StringBuilder vs StringBuffer】+【字符串拼接】...

String详解

注意区分对象和对象的引用

首先来看一下我在jdk中找到的String源代码,这里只截取开头的小小一部分

public final class String

implements java.io.Serializable, Comparable, CharSequence {

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

private final char value[];

从这里可以看出,String类是被final所修饰的,因此String类对象不可变,也不可继承。这里要注意一个误区,字符串对象不可变,但字符串变量所指的值是可变的,即引用地址可变。String变量存储的是对String对象的引用,String对象里存储的才是字符串的值【注意区分对象和对象的引用】。看下面的例子

String str = "abc"; //str是个对象引用

System.out.println(str); //输出abc

str = "abcde"; //不会出错

System.out.println(str); //输出abcde

当给str第二次赋值的时候,对象"abc"并没有被销毁,仍存放在常量池中(String自带),只是让str指向了"abcde"的内存地址,而字符串对象"abcde"是新生成的,即str第二次赋值时并不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。记住,对String对象的任何改变都不影响到原对象,相关的任何改变的操作都会生成新的对象。

String对象是否真的不可变?!

答案并不是的,那么该如何做呢?那就是使用反射(反射不太懂的可以点击链接学习——

从上面的源码可知String的成员变量是private final的,也就是初始化之后不可改变。那么在这几个成员中,value比较特殊,因为它是一个引用变量,而不是真正的对象。value是final修饰的,即final不能再指向其他数组对象,那么我想改变value指向的数组时,比如将数组中的某个位置上的字符变为下划线"_"。因为不能直接通过这个引用去修改数组,那么为了访问到至value这个引用,我们可以使用反射来访问私有成员,反射出String对象中的value属性,进而改变value数组的内容。

public static void testReflection() throws Exception {

// 创建字符串"Hello World" 并赋给引用s

String s = "Hello World";

System.out.println("s = " + s); // 打印出Hello World

// 获取String类中的value字段————Field类获取成员变量

Field valueFieldOfString = String.class.getDeclaredField("value");

valueFieldOfString.setAccessible(true); // 改变value属性的访问权限

value[5] = '_'; // 获取s对象上的value属性的值 改变value所引用的数组中的第5个字符

System.out.println("s = " + s); // 打印出Hello_World

}

下面这个例子将引出两个问题

String str="hello world" 和 String str=new String("hello world") 有什么不同

为什么使用 "==" 和 "equals" 会有不同的结果public static void main(String[] args) {

String str1 = "hello world";

String str2 = new String("hello world");

String str3 = "hello world";

String str4 = new String("hello world");

String str5 = "Hello" + " World";

String str6 = "Hello" + new String(" World");

String str7 = str2.intern();

String ex1 = "Hello";

String ex2 = " World";

String str8 = ex1 + ex2;

System.out.println(str1 == str3); //true

System.out.println(str1 == str2); //false

System.out.println(str2 == str4); //false

System.out.println(str1.equals(str2)); //true

System.out.println(str2.equals(str4)); //true

System.out.println(str1 == str5); //true

System.out.println(str1 == str6); //false

System.out.println(str1 == str7); //true

System.out.println(str1 == str8); //false

}

【运行结果】是 true、false、false、true、true、true、false、true、false

先把下面四大点看懂了,我会在最后写出【解析】

String的两种赋值方式

※ 区分【String str="HW"】和【String str=new String("HW")】

(1)字面量赋值方式     eg:String str = "Hello";

该种直接赋值的方法,JVM会去字符串常量池(String对象不可变)中寻找是否有equals("Hello")的String对象,如果有,就把该对象在字符串常量池中"Hello"的引用复制给字符串变量str,如若没有,就在堆中新建一个对象,同时把引用驻留在字符串常量池中,再把引用赋给字符串变量str。

用该方法创建字符串时,无论创建多少次,只要字符串的值(内容)相同,那么它们所指向的都是堆中的同一个对象。

该方法直接赋值给变量的字符串存放在常量池里

(2)new关键字创建新对象     eg:String str = new String("Hello");

利用new来创建字符串时,无论字符串常量池中是否有与当前值相同的对象引用,都会在堆中新开辟一块内存,创建一个新的对象。

注意:对字符串进行拼接操作,即做"+"运算的时候,分2种情况:

表达式右边是纯字符串常量,那么存放在常量池里面。eg:String str = "Hello" + "World";

表达式右边如果存在字符串引用,也就是字符串对象的句柄,那么就存放在堆里面。eg:String str = str1 + str2;

总结:常量池是方法区的一部分,而方法区是线程共享的,所以常量池也是线程共享的,且它是线程安全的,它让有相同值的引用指向同一个位置,如果引用值变化了,但是常量池中没有新的值,那么就会新建一个常量结果来交给新的引用,对于同一个对象,new出来的字符串存放在堆中,而直接赋值给变量的字符串存放在常量池里。

​​​​​​

字符串比较——区分"=="和"equals"

"==":比较引用变量的地址,即两个对象是否引用同一地址的内容,用"=="时会检测是否指向同一个对象

"equals":比较对象的内容,即两个对象内容上是否相同

字符串用这两种比较方式都是可行的,具体看想要比较什么,总体来看,"=="稍微强大些,因为它既要求内容相同,也要求引用对象相同

intern() 方法

当使用 intern()方法时,会先查询字符串常量池是否存在当前字符串,如果存在,则返回常量池中的引用,若不存在,则将字符串添加到字符串常量池中,并返回字符串常量池中的引用。

【代码解析】

str1 == str3——str1与str3指向常量池中同一个对象,引用对象相同,因此用"=="比较时结果为true

str1 == str2——new会创建一个新的对象放在堆中,str1所指对象在常量池,即使str1与str2内容相同,但并不是同一个对象

str2 == str4——new会创建一个新的对象放在堆中,str2与str4指向不同的对象,即使内容相同

str1.equals(str2)——str1于str2各自引用对象不同,但内容相同,因此用"equals"比较时结果为true

str2.equals(str4)——str2于str4各自引用对象不同,但内容相同,因此用"equals"比较时结果为true

str1 == str5——对字符串进行拼接操作("+"运算)时,表达式右边是纯字符串常量,那么存放在常量池里面,若常量池中有该字符串,则返回该引用

str1 == str6——对字符串进行拼接操作("+"运算)时,表达式右边如果存在字符串引用,也就是字符串对象的句柄,那么就存放在堆里面

str1 == str7——intern()方法会去常量池中找是否存在当前字符,存在则返回引用,该对象引用刚好是str1所指向的

str1 == str8——str8由两个变量拼接,编译期不知道它们的具体位置,所以不会做出优化,必须要等到运行时才能确定,因此新对象的地址和前面的不同。

StringBuilder  & StringBuffer

StringBuilder和StringBuffer类类似于String类,但区别在于String创建的对象是不可改变的,而StringBuilder和StringBuffer这两个类创建对象后都是可以对对象进行修改的。即String为字符串常量,而StringBuilder和StringBuffer均为字符串变量

运行速度(快到慢):StringBuilder > StringBuffer > String

StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行像String对象那样子进行创建和回收的操作,所以速度要比String快很多。

在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

总结

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

字符串拼接五种方法

使用 +

使用 concat

使用 StringBuilder

使用 StringBuffer

使用 StringUtils.join

注:先看完上面对String、StringBuilder和StringBuffer的详解后再看下面的文章会好理解很多的

由于String是Java中一个不可变的类,所以他一旦被实例化就无法被修改,因此所有的所谓字符串拼接,都是重新生成了一个新的字符串。

效率(用时短到长):StringBuilder

(1)"+"是Java提供的一个语法糖,而使用+拼接的字符串,它将String转成了StringBuilder后,再使用StringBuilder.append进行处理。如果不是在循环体中进行字符串拼接的话,直接使用+就好了。

(2)concat方法,其实是new了一个新的String

(3)StringUtils.join也是通过StringBuilder来实现的

(4)StringBuffer在StringBuilder的基础上,做了同步处理,所以在耗时上会相对多一些。

(5)如果在并发场景中进行字符串拼接的话,要使用StringBuffer来替代StringBuilder。因为StringBuilder是线程不安全的,而StringBuffer是线程安全的

其他参考文章:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

阿里日均纳税超1.4亿;AI换脸骗过美侦查;日本民众哄抢令和报纸;辟谣教学楼发现大量金矿;上海拨通首个5G通话;这就是今日大新闻...

今天是4月2日农历二月廿七今天星期二下面是今天的大新闻阿里巴巴日均纳税超1.4亿(IT168)4月1日,阿里巴巴在“2020财年首日”发布消息称:2018全年,阿里巴巴集团和蚂蚁金服集团总计向国家纳税516亿元,同比增长…

大家好!

在博客园申请帐号已经有好长时间了,可是一直也没有写点什么,可能是太忙了吧(其实是懒)!以后我会多写些文字,毕竟这是一件好事。转载于:https://www.cnblogs.com/hubin/archive/2004/08/16/33928.html

腾讯大湘网某处csrf(city.hn.qq.com)可投诉刷留言

触发点: http://city.hn.qq.com http://city.hn.qq.com/auto/cshop&mbbs&id668 POST /msgboard/message.php HTTP/1.1 Host: c1.city.qq.com Connection: keep-alive Content-Length: 201 Cache-Control: max-age0 Accept: text/html,application/xhtmlxml,…

c#:细说时区、DateTime和DateTimeOffset在国际化中的应用

先说下结论:如果系统不考虑全球化的话,那么我们不用考虑时区的问题,因为我们可以认为中国境内的计算机全部用的是北京时间。1. 时区的来源和划分地球自转一圈是360度,共24小时,所以1小时15度,即&#xff1a…

java注解 sql_mybatis中注解映射SQL示例代码

前言本文主要给大家介绍了关于mybatis注解映射sql的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:结果集分页有时我们需要处理海量数据,由于数据量太大,所以不能一次取出所有的数…

超赞的“数据与算法之美”资料分享!

相信,一直关注着我们的同学们都知道,小思妹分享了好多好多的资料给大家。为了方便新来的同学自取,小思妹又重新整理了一遍,直接点以下标题即可跳转!这是我见过的最全的训练数据集,没有之一!送你…

mysql服务的启动和停止 net stop mysql net start mysql

第一招、mysql服务的启动和停止 net stop mysql net start mysql 第二招、登陆mysql 语法如下: mysql -u用户名-p用户密码 键入命令mysql -uroot -p,回车后提示你输入密码,输入12345,然后回车即可进入到mysql中了,mysq…

在ASP.NET Core微服务架构下使用数据库切分和扩展, 并用JMeter进行负载测试

原文链接:https://itnext.io/how-to-scale-an-asp-net-core-microservice-and-sharded-database-load-test-with-jmeter-1a8c7292e7e3现在,您将扩展应用程序并运行多个微服务和数据库的容器实例。您将使用Docker Compose和HAProxy负载均衡器:…

mysql5.5 mysqli_php5.5.38增加mysqli扩展

php5.5.38增加mysqli扩展发布时间:2020-08-28 03:43:17来源:51CTO阅读:1148作者:xingyun2010编译的时候正常:./configure --prefix/usr/local/mysqli --with-php-config/usr/local/php/bin/php-config --with-mysqli/u…

每日一笑 | 周杰伦到底什么时候才发新专辑?

全世界只有3.14 % 的人关注了数据与算法之美(图源网络,侵权删)

GARFIELD@10-18-2004

子非猫转载于:https://www.cnblogs.com/rexhost/archive/2004/10/18/53799.html

【荐】牛逼的WPF动画库:XamlFlair

【荐】牛逼的WPF动画库:XamlFlair原文链接:https://github.com/XamlFlair/XamlFlair翻译:沙漠尽头的狼(本文未全文翻译,建议阅读原文了解更多)XamlFlairXamlFlair库的目标是简化常见动画的实现,并允许开发人员使用几行…

Python编程系列教程第13讲——隐藏数据和封装

视频地址:http://www.56.com/u88/v_OTM5NjU0MjE.html#fromoutpvidOTM5NjU0MjE 普及网络安全知识,推动信息技术发展。 为祖国的网络安全撑起一片蓝天,为网络安全爱好者构建一方家园。 欢迎来到灰帽程序员论坛,我们的网址是&#xf…

HijackThis日志细解【简明教程增强版】(五)

(九)组别——O51. 项目说明O5项与控制面板中被屏蔽的一些IE选项相关,一些恶意程序会隐藏控制面板中关于IE的一些选项,这可以通过在control.ini文件中添加相关命令实现。2. 举例O5 - control.ini: inetcpl.cplno 这里隐藏了控制面板…

java字符串如何输出_java字符串如何输出

在Java编程中,我们常常用 System.out.println(); 来输出字符串。System.out.println();System是一个类,继承自根类Objectout是类PrintStream类实例化的一个对象,且是System类的静态成员变量println()是类PrintStream的成员方法,被…

简单易懂的自动驾驶科普知识

全世界只有3.14 % 的人关注了数据与算法之美有不少人问我人工智能和自动驾驶的技术问题,我作为一个主业是后端开发的老码农可是回答不了啊!今天转载一篇自动驾驶大拿写的文章,学习一下。先来一张各大车企自动驾驶技术的分级图,大致…

图像处理工具包ImagXpress中如何设置上下文菜单

ImagXpress 是世界上最先进的彩色映像和照片图像处理工具包,有着.NET、COM、VC三种组件形式。ImagXpress可以为开发者构建的应用程序提供图像浏览、编辑、打印、TWAIN扫描、文件格式转换等优秀的功能。本文先来看看它的一些基础设置,如何设置上下文菜单。…

Educational Codeforces Round 157 (Rated for Div. 2)

Educational Codeforces Round 157 (Rated for Div. 2) A 模拟 #include <bits/stdc.h>using namespace std;const int N 3e5 10;void solve() {int x , y , k;cin >> x >> y >> k;if(y < x){cout << x << endl;}else if(x k >…

WPF TextBox限制只能输入数字的两种方法

文本框中只能输入数字&#xff0c;一个常见的功能喽&#xff0c;今天就来看看如何实现它~下面就看看代码思路都写在xaml里面了&#xff0c;MainWindow.xaml:<Window x:Class"wpfcore.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/present…

r.java没有生成_R.java 常见问题(R.java文件没有生成 )

1、选择菜单 Project >> Clean &#xff0c;前提是勾选上 Bulid Automatically(自动构建部署) &#xff0c; 点Clean后会重新构建项目&#xff0c;因为一般情况下&#xff0c;R.java文件在这个时候会重新更新生成一边&#xff0c;如果工程有错&#xff0c;就不会自动生成…