使用String类应该注意的点

版权声明:转载需要经过同意 https://blog.csdn.net/m0_37907797/article/details/80141990

        第一次写博客,想以博客的方式一边记录我的学习。不过感觉写博客真的好花时间啊。希望自己能坚持下去。文章如若有不赞同的地方,望指点江山,感激不尽。

1.String对象是不可变 String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象。(通过查源码你会发现,String类是用final修饰的)

         2.当我们使用了‘+’,‘+=’操作符,例如

                                                                      Stingmango = “mango”;

                                                                      Strings = “abc” + mango + “def” + 47;

时,编译器是如何工程的呢?实际上,编译器会为我们自动创建一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次StringBuilderappend()方法,总共四次。最后调用toString()生成结果,并存为s;

看下面两个方法:

public class TestStringBuilder {
       public String A(String[] fields){
              String result = "";
              for(int i = 0; i < fields.length; i++){
                     result += fields[i];
              }
              return result;
       }
       
       public String B(String[] fields){
              StringBuilder result = new StringBuilder();
              for(int i = 0; i < fields.length; i++){
                     result.append(fields[i]);
              }
              return fields.toString();
       }
}

两个方法虽然实现了同样的功能,但是在效率上却是完全不一样的。对于第一个方法A,不难理解,每次循环都会创建一个StringBuilder对象,然后在在调用两次append()方法。而对于第二个方法B,由于在循环体前面就已经创建了StringBuilder对象,所以在循环体里不会在创建StringBuilder对象。显然,对于这种情况,

采用显shi4着创建StringBuilder对象的方式,比第一种方法编译器隐式替我们高效的多。如果你已经知道最终的字符串大概有多长,那预先指定StringBuilder的大小还可以避免多次重新分配缓冲,效率会更快。

请看下面一个方法(有关字符串效率操作):

 

public String C(String[] key, String[] value){StringBuilder result = new StringBuilder();for(int i = 0; i < key.length && i < value.length; i++){result.append(key[i]);result.append(":");result.append(value[i]);result.append(“,”);}return result.toString();
}

对于这个方法,每次循环都会调用四次append()方法,一点点着把keyvalue拼接起来。可能有人会觉得太麻烦,想走捷径,例如这样写:append(key[i] + “:”+ value[i] + “,”);如果这样写,编译器在处理的时候就会为另外创建一个StringBuilder对象来处理括号内的字符串操作,显然,这种方法最终还是会调用四次append()方法,而且还另外创建了一个StringBuilder对象,效率低。

无意识的递归:

    java中的类从根本上都是继承自Object,标准容器类自然也不例外。因此容器类都有toString()方法,并且覆写了该方法,使得它生成的Sting结果能够表达容器自身,以及容器所包含的对象,例如当你调用ArrayList.toString()时,它会遍历ArrayList中包含的所有对象,并且调用每个元素的toString方法。

考虑下面一个问题:如果你希望用toString()方法打印出对象的内存地址,也许你会考虑使用this关键字:
public class Student {
	@Override
	public String toString() {
		return "student address:" +  this + "\n";	
	}
	
	public static void main(String[] args) {
		List<Student> list = new ArrayList<>();
		for(int i = 0; i < 10; i++){
			list.add(new Student());
		}
		System.out.println(list);
	}
}

当年执行这段程序的时候,你会发现这段程序抛出一段非常长的异常。为什么会这样呢?实际上,当你运行

    “studentaddress:” + this + “\n”

这句代码时,发生了类型转换,由Student类型(this)转成String类型,那它是怎么转换的呢?实际上,当编译器看到一个String对象后面跟着一个“+”,而在后面的对象不是String时,编译器就会试着调用该对象的toString()方法把它变成String对象,也就是调用了this.toString(),于是,就发生了递归调用。

如果你真的像打印对象的地址,那么应该调用Objiect.toString()方法,即应该调用super.toString()方法。
注:以上的知识点,大都来自编程思想这本书的学习。由于第一次写有些不大会描述,又感觉书上有些描述的很好,就直接摘抄了。




猜你喜欢

转载自blog.csdn.net/m0_37907797/article/details/80141990