zoukankan      html  css  js  c++  java
  • java基础之字符串

    以下内容摘自《java编程思想》第十三章。

    1. 不可变 String

    String 对象是不可变对象,String 类中每一个看起来会修改 String 值的方法,实际上都是创建了一个全新的 String 对象,以包含修改后字符串的内容,而最初的 String 对象丝毫未动。看如下的代码:

    import static java.lang.System.*;
    
    public class Immutable{
    	public static String upcase(String s){
    		return s.toUpperCase();
    	}
    
    	/*
    		结果为:howdy HOWDY howdy
    	*/
    	public static void main(String[] args){
    		String q = "howdy";
    		out.println(q);
    		String qq = upcase(q);
    		out.println(qq);
    		out.println(q);
    	}
    }
    

    2. 重载 "+" 与StringBuilder

    String 是不可变的,这会带来一定的效率问题。首先看一下这段代码:

    public class Concatenation{
    	String mango = "mango";
    	String s = "abc"+mango+"def"+47;
    	System.out.println(s);
    	// 结果 abcmangodef47
    }
    

    可以想象一下,这段代码可能是这样工作的:String 可能有一个 append 方法,它会生成一个新的 String 类,以包含 “abc” 与 mango 连接后的字符串。然后,该对象再与 “def” 相连,生成另一个 String 对象,以此类推。

    这种工作方式当然行得通,但是为了生成最终的 String,此方式会产生大量的需要垃圾回收的中间对象,这样运行性能实在是糟糕。那么上面的代码是否真的是这样工作的呢?书中利用了 JDK 内置的工具 javap -c Concatenation 反编译上面的代码,发现,在上面的 "+" 操作中,编译器自作主张的使用了 StringBuilder 类,因为它更高效。每一次 "+" 操作,都调用了 StringBuilder.append 方法,最后使用 toString 方法返回字符串。

    上面对于 "+" 操作符工作流程的解释说明编译器会自动地优化性能,但是,它也不能做到完美,比如在循环中,经过循环一次, + 操作符就会产生一个 StringBuilder,所以,在循环中如果要对字符串进行操作,建议使用 StringBuilder 对象。

    StringBuilder 是 java SE5 引入的,在这之前 java 用的是 StringBuffer,后者是线程安全的,因此开销也会更大些,所以,在 java SE5/6 中,字符串操作应该会更快一点。

    3. 无意识的递归

    java 中每个类从根本上都是继承自 Object,标准容器类自然也不例外。因此容器类有 toString 方法,并覆写了该方法。例如 ArrayList.toString() 会遍历容器中所有的对象,并调用对象的 toString 方法。如果我们想要在 toString 方法中打印出对象的内存地址,也许会考虑使用 this 关键字。

    import java.util.ArrayList;
    import java.util.List;
    
    public class InfiniteRecursion {
    	public String toString(){
    		return "InfiiniteRecursion address"+this;
    	}
    	
    	public static void main(String[] args){
    		List<InfiniteRecursion> v = new ArrayList<InfiniteRecursion>();
    		for(int i=0;i<10;i++){
    			v.add(new InfiniteRecursion());
    		}
    		System.out.println(v);
    	}
    }
    

    但是上面的代码运行会出现 java.lang.StackOverflowError,这是为什么呢?原因出现在 toString 方法中,编译器看到字符串 "InfiiniteRecursion address" 后面跟着一个 "+" ,而再后面的对象不是 String,于是编译器试着将 this 转换为 String 对象,怎么转换呢?这是通过调用 toString 方法,于是就发生了递归调用。如果在上面的例子中想要打印出对象的内存地址,应该调用 super.toString 方法。

    以上是我对书中的一些总结,有什么好的看书建议欢迎提出来一起交流分享。

  • 相关阅读:
    LC.225. Implement Stack using Queues(using two queues)
    LC.232. Implement Queue using Stacks(use two stacks)
    sort numbers with two stacks(many duplicates)
    LC.154. Find Minimum in Rotated Sorted Array II
    LC.81. Search in Rotated Sorted Array II
    LC.35.Search Insert Position
    前后端分离:(一)
    Redis基本使用(一)
    GIT篇章(二)
    GIT篇章(一)
  • 原文地址:https://www.cnblogs.com/firepation/p/9481883.html
Copyright © 2011-2022 走看看