java中String类型变量的赋值问题
第一节 String类型的方法参数
运行下面这段代码,其结果是什么?
package com.test; public class Example { String str = new String("good");
char[] ch = { 'a', 'b', 'c' }; public static void main(String[] args) {
Example ex = new Example();
ex.change(ex.str, ex.ch);
System.out.println(ex.str);
System.out.println(ex.ch);
} public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'g';
} }
结果如下:
good
gbc
解说:java 中String是 immutable的,也就是不可变,一旦初始化,引用指向的内容是不可变的(注意:是内容不可变)。
我们再来看下面这段代码,它的运行结果是什么?
package com.test; public class Example { String str = new String("good");
char[] ch = { 'a', 'b', 'c' }; public static void main(String[] args) {
Example ex = new Example();
ex.change(ex.str, ex.ch);
System.out.println(ex.str);
System.out.println(ex.ch);
} public void change(String str, char ch[]) {
str = str.toUpperCase();
ch = new char[]{ 'm', 'n' };
} }
结果如下:
good
abc
结合前面的解释进行理解,这个结果是不是在意料之中?!
根据JDK中java.lang.String的源码进行分析,从中可以得出String类型的对象不可变的原因,大致上有如下两个:
1、java.lang.String类型在实现时,其内部成员变量全部使用final来修饰,保证成员变量的引用值只能通过构造函数来修改;
2、java.lang.String类型在实现时,在外部可能修改其内部存储值的函数实现中,返回时一律构造新的String对象或者新的byte数组或者char数组;
仅凭第1点还不能保证其不可变特性:假如通过String类型的toCharArray方法可以直接访问String类型内部定义的char数组,那么即便String类型内部的char数组使用了final来修饰,也仅仅保证这个成员变量的引用不可变,而无法保证引用指向的内存区域不可变。
第2点保证了外部不可能修改java.lang.String类型对象的内部属性,从而保证String对象是不可变的。
第二节 String类型变量的赋值
2.1 String变量赋值方式:s2=new String(s1)
下面这段代码的运行结果是什么
package com.soft; public class ExecutorsDemo { public static void main(String[] args) {
String s1="abc"+"def";
String s2=new String(s1);
if(s1.equals(s2))
System.out.println("equals succeeded");
if(s1==s2)
System.out.println("==succeeded");
}
}
结果:
equals succeeded
解说:上述代码中,s1与s2指向不同的对象,但是两个对象的内容却是一样的,故“s1==s2”为假,s1.equals(s2)为真。
此处我们来细说一下"=="与equals的作用:
(1)"=="操作符的作用
A、用于基本数据类型的比较
B、判断引用是否指向堆内存的同一块地址
(2)equals的作用
用于判断两个变量是否是对同一个对象的引用,即堆中的内容是否相同,返回值为布尔类型
2.2 String变量赋值方式:s2 = s1
package com.soft; public class ExecutorsDemo { public static void main(String[] args) {
String s1 = new String("java");
String s2 = s1; System.out.println(s1==s2);
System.out.println(s1.equals(s2));
}
}
结果:
true
true
解说:如果理解了前面那个例子的运行情况,那么这个就是一目了然的事情,此处s1与s2指向同一个对象,"=="操作符的作用之一就是判断引用是否指向堆内存的同一块地址,equals的作用是判断两个变量是否是对同一个对象的引用(即堆中的内容是否相同),故此处均输出“true”
第三节 将字符数组或字符串数组转换为字符串
此处再补充两个应用场景
一、将字符数组转换为字符串
下面代码中的两种方式均可直接将字符数组转换为字符串,不需要遍历拼接
package com.test; public class Main { public Main() {
} public static void main(String[] args) {
char[] data = {'a', 'b', 'c'};
// String str = new String(data);
String str = String.valueOf(data);
System.out.println(str);
} }
此处可以看一下其他作者的文章以深入理解:【Java】数组不能通过toString方法转为字符串 http://www.cnblogs.com/ningvsban/p/3955483.html
二、将字符串数组转换为字符串
下面的代码是我们常用的方式,循环拼接
package com.test; public class Main { public Main() {
} public static void main(String[] args) {
String[] ary = {"abc", "123", "45"};
String s = "";
for(String temp : ary) {
s=s.concat(temp);//和下面的一行二选一即可
// s += temp;
}
System.out.println(s);
} }
上述代码段不需要过多解释了
第四节 StringBuffer和StringBuilder
提到String,就不得不提一下JDK中另外两个常用来表示字符串的类,StringBuffer和StringBuilder。在编写java代码的过程中有时要频繁地对字符串进行拼接,如果直接用“+”拼接的话会建立很多的String型对象,严重的话会对服务器资源和性能造成不小的影响;而使用StringBuilder和StringBuffer能解决以上问题。根据注释,StringBuffer可谓老资格了,从JDK1.0时即伴随Java征战世界,而StringBuilder直到JDK1.5时才出现。面试时,StringBuffer和StringBuilder的区别也是常问的话题,StringBuffer是线程安全的,而StringBuilder不是线程安全的。
一、StringBuffer和StringBuilder的共同点:
1、用来完成字符串拼接操作;
2、都是可变对象,对象内的字符缓存会随着拼接操作而动态扩展;
3、构造时传入内部缓存大小时,可以降低缓存扩展的次数,明显提升字符串拼接操作的效率;
二、StringBuffer和StringBuilder的区别:
1、StringBuilder的方法都是线程不安全的,从另外一个角度讲,StringBuilder类型的对象在做字符串拼接操作时,由于少了线程同步的操作,执行效率上有很大提升;
2、StringBuffer的方法都加上了synchronized关键字,因而在一定的场景下,StringBuffer类型的对象都是线程安全的,但在执行效率上,由于多了线程同步的操作,因而会有少许的损失;
在大多数场景下,字符串拼接操作都是不需要考虑多线程环境下对结果的影响的,因而使用StringBuilder类型可以提升代码的执行效率。
在多个线程的代码中共享同一个StringBuffer类型的对象时,需要关注synchronized关键字对最终结果的影响。由于StringBuffer类的实现中,仅仅对每个方法使用了synchronized修饰,这只能保证在多线程场景下,访问StringBuffer对象的同一个方法时可以保证最终结果的一致性,假如一个线程访问A方法,另外一个线程方法B方法,则由于加锁对象的不同,可能会出现不一致的现象,这是需要程序员特别要注意的地方。类似的,可以参考Vector的实现和应用场景。
针对上面的将字符串数组转换为字符串,可以借助上面提到的StringBuilder(当然StringBuffer也可以),代码如下:
package com.test; public class Main { public Main() {
} public static void main(String[] args) {
String[] ary = {"abc", "123", "45"};
StringBuilder sb = new StringBuilder();
for(int i = 0; i < ary.length; i++){
sb. append(ary[i]);
}
String newStr = sb.toString();
System.out.println(newStr);
} }
参考资料
这里有两篇文章,值得一读:
(1)三分钟理解Java中字符串(String)的存储和赋值原理 http://blog.csdn.net/zhuiwenwen/article/details/12351565
(2)Java之内存分析和String对象 http://www.cnblogs.com/devinzhang/archive/2012/01/25/2329463.html
java中String类型变量的赋值问题的更多相关文章
- 关于JAVA中string直接初始化赋值和new的区别,是否可以联系到int[]的情况
String str1 = "ABC"; String str2 = new String("ABC"); String str1 = “ABC”;可能创建一个 ...
- java中String new和直接赋值的区别
Java中String new和直接赋值的区别 对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才 ...
- Java中String对象创建机制详解()
一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...
- 探秘Java中String、StringBuilder以及StringBuffer
探秘Java中String.StringBuilder以及StringBuffer 相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问 到的地方,今天就来和大家一起学习 ...
- java中String类学习
java中String类的相关操作如下: (1)初始化:例如,String s = “abc”; (2)length:返回字符串的长度. (3)charAT:字符操作,按照索引值获得字符串中的指定字符 ...
- Java中String对象的不可变性
首先看一个程序 package reverse; public class Reverse { public static void main(String[] args) { String c1=n ...
- java中String类、StringBuilder类和StringBuffer类详解
本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html 版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolp ...
- Java中String类型细节
Java中String类型细节 一 . String两种初始化方式 1 . String str1= “abc”;//String类特有的创建字符对象的方式,更高效 在字符串缓冲区中检测”abc”是否 ...
- 在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?
最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下. 1.String的不可变String类被final修饰,是不可继承和 ...
随机推荐
- 【mysql】关于innodb中MVCC的一些理解
一.MVCC简介 MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代 ...
- SQL Server 2008 R2——VC++ ADO 操作 参数化查询
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- solrcloud 配置实践
1.环境 3台虚拟机:192.168.26.129.192.168.26.131.192.168.26.132,使用命令sudo iptables -F 关闭防火墙 Solr: solr-6.1.0 ...
- 限制input输入类型(多种方法实现)
1.只能输入和粘贴汉字 <input onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" onbeforepaste= ...
- c++ Windows Socket实现最简单的C/S网络通信(TCP)
1.服务器端代码: #include<iostream> #include<WinSock2.h> #pragma comment(lib, "ws2_32.lib& ...
- docker基础命令详解
Commands: attach Attach to a running container build Build an image from a Dockerfile commit ...
- android ndk编译x264开源(用于android的ffmpeg中进行软编码)
http://blog.csdn.net/u012917616/article/details/40921833 不废话,直接上.sh脚本: export NDK=/home/xxx/my_softw ...
- AngularJS模块加载
配置块 在模块的加载阶段,AngularJS会在提供者注册和配置的过程中对模块进行配置.在整个AngularJS的工作流中,这个阶段是唯一能够在应用启动前进行修改的部分. angular.module ...
- Sql-oracle and sqlserver differences
1.string contact operator Sqlserver use + or contact(sqlserver 2012) In oracle, you can also use con ...
- uva 572 oil deposits——yhx
Oil Deposits The GeoSurvComp geologic survey company is responsible for detecting underground oil d ...