Thinking in java-35 String 字符串

来源:互联网 发布:无间道1的知乎 编辑:程序博客网 时间:2024/06/05 01:07

1. immutable不可改变特性

String类对象都是不可修改的。如果我们去查阅JDK文档关于String类的信息,我们将发现所有看起来修改了String内容的方法其实是返回了一个全新的对象包含了这部分修改内容。原始的String字符串依然保持原封不动,未做过任何修改。这种设定保证了的代码很容易写,而且易于被人理解。
Objects of the String class are immutable. If you examine the JDK documentation for the String class, you’ll see that every method in the class that appears to modify a String actually creates and returns a brand new String object containing the modification. The original String is left untouched.
This is an important guarantee, since it makes code easier to write and understand.

2. String的’+’ & ‘+=’

因为String类型的对象是read-only的,所以在字符串引用上所做的修改不可能会影响其它的引用。但是String的这种imutable特性也又一些效率上的代价存在。

另:’+’&’+=’是java语言中唯二被重载的操作符号,Java语言不允许程序猿重载任何其他的操作符。
所以一般在做对于String的修改操作时,一般会用StringBuilder作中间处理,减少对象的连续创建和释放带来的系统性能开销。

package com.fqy.blog;import java.util.Random;public class StringBuilderDemo {    private Random random = new Random();    public String toString() {        StringBuilder sb = new StringBuilder("[");        for (int i = 0; i < 10; i++) {            sb.append(random.nextInt(100));            sb.append(", ");        }        /*         * StringBuilder.delete(int start, int end) start inclusive, and end         * exclusive         */        sb.delete(sb.length() - 2, sb.length());        sb.append("]");        // return the number of unicode units in the string.        System.out.println(sb.length());        // System.out.println(sb.toString().length());        return sb.toString();    }    public static void main(String[] args) {        StringBuilderDemo sbd = new StringBuilderDemo();        System.out.println(sbd);    }}//Running result:39[32, 4, 54, 83, 43, 16, 35, 52, 64, 31]

3. 关于toString()方法的一个栈溢出的问题

当编译器看到一个String对象,其后跟着的是一个非String类型的东西时,它会试图将其解析成一个String类型的对象。问题出现了,它会不断地调用自身,直到栈空间耗尽。控制台被不断的栈溢出所淹没,不知所措。
解决方式之一是:调用父类的方法super.toString()方法。

package com.fqy.blog;public class StackFlowDemo {    @Override    public String toString() {        // This will cause infinite loop here this way.        return "Infinite Recursion address: " + this + "\n";        // This will work.        // return super.toString();    }    public static void main(String[] args) {        System.out.println(new StackFlowDemo());    }}//Running result:Exception in thread "main" java.lang.StackOverflowError    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:449)    at java.lang.StringBuilder.append(StringBuilder.java:136)    at java.lang.StringBuilder.<init>(StringBuilder.java:113)    at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)    at java.lang.String.valueOf(String.java:2994)    at java.lang.StringBuilder.append(StringBuilder.java:131)    at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)    at java.lang.String.valueOf(String.java:2994)    at java.lang.StringBuilder.append(StringBuilder.java:131)    at com.fqy.blog.StackFlowDemo.toString(StackFlowDemo.java:7)    at java.lang.String.valueOf(String.java:2994)    ...

4. 关于String对象的内存存储问题

这里展示几个常见方法:toCharArray()/valueOf()/intern().
其中关于intern() 方法存在的意义的问题,stackoverflow上有详细问题,具体参见这里和这里。
Q:What is String interning?–什么是intern()方法?
A:Basically doing String.intern() on a series of strings will ensure that all strings having same contents share same memory. 一般说来,我们调用intern()方法,将会使得有相同内容的String对象在内存中只有一份存储。
这样做的好处是降低了程序对于内存的需求;但问题在于这部分缓存是被JVM的permanent memory区所维护的,永久区内存大小通常比heap区内存要小得多,所以如果不是对象特别多的话,不要使用intern()方法。
Q:到底我们应该什么时候使用intern()方法呢?
A:String.intern()方法在该String对象在String pool中被发现存在时,返回该对象的引用;否则则会在String pool中插入一个新对象,并返回新对象的引用。
Q:intern在String.intern()的应用?
A:这里分为2种情形。1.java自动将字符串字面值sting literals转换为intern的,比如String str1 = “this is literal str”;。这意味着,==对于这类的String类型数据就像基本数据类型一样比如int . 2.对于使用new String()方法创建的String对象,是需要使用intern()方法保证其内存空间的唯一性的。

package com.fqy.blog;public class StrOpr {    public static void main(String[] args) {        int num = 12345;        String str = "fqyuan";        String str1 = new String("fqyuan");        String str2 = "fqyuan";        // 1.String.toCharArray(), return character array of the string        char[] arr = str.toCharArray();        // 2. static method, convert the input to String.        String intVal = String.valueOf(num);        // 3.This is a special case that need to be taken care of.        String inString = str.intern();        System.out.println(arr);        System.out.println(intVal);        System.out.println(inString);        if (str == str1)            System.out.println("str == str1");        if (str == str2)            System.out.println("str == str2");        if (str == str1.intern())            System.out.println("str == str2.intern()");        //an equality check on the contents of the two Strings.        if (str.equals(str1))            System.out.println("str equals str1");    }}//Running result:fqyuan12345fqyuanstr == str2str == str2.intern()str equals str1
原创粉丝点击