Thinking in java-35 String 字符串

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:
fqyuan
12345
fqyuan
str == str2
str == str2.intern()
str equals str1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值