String
1、String对象是不可变的。
2、String类中每一个看起来会修改String值得方法,实际上都是创建一个全新的String对象,以包含修改后的字符串内容。最初的String对象丝毫未动。
3、方法调用,String为参
public class Test01 {
public static void main(String[] args) {
String oldStr = "HelloWorld";
System.out.println(oldStr);//HelloWorld
String newStr = upCase(oldStr);
System.out.println(newStr);//HELLOWORLD
System.out.println(oldStr);//HelloWorld
}
public static String upCase(String temp){
return temp.toUpperCase();
}
}
3.1. 调用upCase(),String对象作为参数时,都会复制一份引用,而该引用所指对象其实一直待在单一的物理位置上。
3.2 upCase()方法中,
1)引用名称temp,只有运行upCase()的时候,局部引用temp才存在;
2)upCase()运行结束,temp就消失了;
3)upCase()的返回值,也只是最终结果的引用
4、“+” 与 StringBuilder
public class Test02 {
public static void main(String[] args) {
String str = "love" ;
String newStr = "I " + str + " code" + " very much" ;
System.out.println(newStr);//I love code very much
}
}
4.1 该代码工作可能为,"I"与str连接后生成一个新的字符串,然后该新字符串再与"code"相连生成一个新的String对象,以此类推。得到最终String。该工作方式行得通,但会产生一大堆需要垃圾回收的中间对象。
4.2 反编译得出结论,上诉代码,编译器创建了一个StringBuilder对象,用以构造最终的String。编译器会为你的代码自动优化
5、编译器会将"+"优化成StringBuilder
public class Test03 {
public String useString(String[] fields){
String str = "";
for(int i=0 ; i<fields.length ; i++){
str += fields[i];
}
return str;
}
public String useStringBuilder(String[] fields){
StringBuilder sb = new StringBuilder();
for(int i=0 ; i<fields.length ; i++){
sb.append(fields[i]);
}
return sb.toString();
}
}
5.1 编译器会将"+"优化成StringBuilder,反编译得出:
5.2 useString(),StringBuilder是在循环内构造的,每循环一次,就会创建一个新的StringBuilder对象
5.3 useStringBuilder(),只生成了一个StringBuilder对象。而且,如果提前知道字符串的大概长度,可以显示的创建StringBuilder并指定大小,这样可以避免多次重新分配缓冲。
注:StringBuilder调用append()时,若写成append(a+":"+c),那么编译器会为你创建另外一个StringBuilder对象来处理括号内的字符串操作
6、无意识递归
6.1 java中每个类根本上继承自Object,每个类都有toString()方法,并且覆写了该方法。
如ArrayList.toString(),它会遍历ArrayList中包含的对象,调用每个元素的toString()方法
public class Test04 {
public static void main(String[] args) {
List<Animal> list = new ArrayList<>();
for(int i=0 ; i<5 ; i++){
list.add(new Animal(i));
}
System.out.println(list);//[老鼠, 牛, 老虎, 张飞, 张飞]
}
}
class Animal{
private String name;
public Animal(int i){
switch(i){
case 0: this.name = "老鼠";
return;
case 1: this.name = "牛";
return;
case 2: this.name = "老虎";
return;
default: this.name = "张飞";
}
}
public String toString(){
return this.name;
}
}
6.2 如果你希望toString()方法打印出对象的内存地址,也许你会考虑用this关键字,例子中Animal类改为
class Animal{
//其它省略...
public String toString(){
return this.name + ",classAddress=" + this;
}
}
6.3 然后你就会看到异常,java.lang.StackOverflowError。
当执行 this.name + ",classAddress=" + this 时,Animal类型转换成了String类型。
编译器看到一个String对象后面跟着一个"+",而后面不是String对象,于是编译器试着将this转成一个String。于是又调用了this上的toString()方法,就发生了递归调用。
6.4 正确的打印对象的内存地址,应该调用Object.toString()。所以不能使用this,要使用super.toString()。
正确代码为:
public class Test04 {
public static void main(String[] args) {
List<Animal> list = new ArrayList<>();
for(int i=0 ; i<3 ; i++){
list.add(new Animal(i));
}
System.out.println(list);
//[老鼠,classAddress=com.test01.thinking.mystring.Animal@5594a1b5,
// 牛,classAddress=com.test01.thinking.mystring.Animal@79b4d0f,
// 老虎,classAddress=com.test01.thinking.mystring.Animal@6b2fad11]
}
}
class Animal{
private String name;
public Animal(int i){
switch(i){
case 0: this.name = "老鼠";
return;
case 1: this.name = "牛";
return;
case 2: this.name = "老虎";
return;
default: this.name = "张飞";
}
}
public String toString(){
return this.name + ",classAddress=" + super.toString();
}
}
网友评论