java定义string变量赋值吗_java中String类型变量的赋值问题第⼀节 String类型的⽅法参数
运⾏下⾯这段代码,其结果是什么?
st;
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的,也就是不可变,⼀旦初始化,引⽤指向的内容是不可变的(注意:是内容不可变)。
也就是说,假设代码中有String str = “aa”;str=“bb”;,则第⼆条语句不是改变“aa”原来所在存储地址中的内容,⽽是另外开辟了⼀个空间⽤来存储“bb”;同时由于str原来指向的“aa”现在已经不可达,jvm会通过GC⾃动回收。
在⽅法调⽤时,String类型和数组属于引⽤传递,在上述代码中,str作为参数传进change(String str, char ch[]) ⽅法,⽅法参数str指向了类中str指向的字符串,但str= "test ok"; 语句使得⽅法参数str指向了新分配的地址,该地址存储“test ok”,⽽原来的str仍然指
向“good”。对于数组⽽⾔,在change⽅法中,⽅法参数ch指向了类中ch指向的数组,ch[0] = 'g';语句改变了类中ch指向的数组的内容
我们再来看下⾯这段代码,它的运⾏结果是什么?
st;
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 = UpperCase();
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”
第三节 将字符数组或字符串数组转换为字符串
此处再补充两个应⽤场景
⼀、将字符数组转换为字符串
下⾯代码中的两种⽅式均可直接将字符数组转换为字符串,不需要遍历拼接
st;
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);
}
}
⼆、将字符串数组转换为字符串
下⾯的代码是我们常⽤的⽅式,循环拼接
st;
public class Main {
public Main() {
}
public static void main(String[] args) {
String[] ary = {"abc", "123", "45"};
String s = "";
for(String temp : ary) {
at(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也可以),代码如下:
st;
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++){java定义一维数组并赋值
sb. append(ary[i]);
}
String newStr = sb.toString();
System.out.println(newStr);
}
}
参考资料
这⾥有两篇⽂章,值得⼀读:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论