java中String学习

来源:互联网 发布:韩国聊天软件talk 编辑:程序博客网 时间:2024/05/26 12:06

1. String的不可变性

一旦一个String对象在内存中创建, 它将不可改变, 所有String类中方法并不是改变String对象自己, 而是重新创建一个新的String对象 .
这里写图片描述
第一行在常量池中创建一个”abc”对象,
第二行进行截取, 其实是重新创建一个对象, 然后让a重新指向这个截取对象 .
但是原来”abc”对象并没有变化 , 只是没有引用指向它, 最后被垃圾回收 .
也就是”abc”, 一旦创建就不会被修改 . 这就是不可变性 .
查看String源码 :
这里写图片描述
它的成员变量都是final, 尤其是value成员, 被final修饰, 表示这个变量一旦通过构造函数生成就不能被改变 .
所以String的不可变性并不是因为类被声明final(类被声明final只能代表可不可被继承), 真正决定不可变性, 是成员变量都被声明为final .

2. 代码

 *常量 : final String a = "abc", 被final修饰, 那么a就是常量.
public static void main(String[] args) {        /**         * 1.常量池         * JVM存在一个常量池,其中保存很多String对象,并且可以被共享,提高效率         * 由于String类中成员是final, 它的值一旦创建不能被修改         * 字符串池由String类维护, 可以调用intern方法访问字符串池 .          */        // 字符串池创建一个对象        String s1 = "abc";        // 字符串池中存在"abc",所以这次不需要创建对象        String s2 = "abc";        // 所以两个地址指向一致 .         System.out.println("s1 == s2:"+(s1 == s2)); // true        /**         * 2.new String("")         */        // 创建两个对象, 一个存在字符串池中, 一个存在堆中        String s3 = new String("abc");        // 池中已经存在"abc"对象, 所以只在堆中创建        String s4 = new String("abc");        // 所以s3和s4不相等,都在堆中,指向的内存区域不同        System.out.println("s3 == s4:"+(s3 == s4)); // false        // 一个在pool中另一个在堆中        System.out.println("s1 == s3:"+(s1 == s3)); // false        /**         * 3.常量的值在编译时已经确定(优化)         * 这里"ab"和"cd"都是常量, 因此"+"之后值在编译时确定         * 等同于 str = "abcd"         */        String s5 = "ab" + "cd";        String s6 = "abcd";        System.out.println("s5 == s6:"+(s5 == s6)); // true        /**         * 4.局部变量s7,s8存储两个拘留字符串对象的地址 .          * 那么下面(s7+s8)原理 :         * 运行期JVM首先会在堆中创建一个StringBuilder对象,         * 然后利用s7指向的拘留字符串完成初始化         * 然后调用append方法完成对s8指向的字符串进行合并         * 然后调用toString方法在堆中创建一个String对象         * 最后将刚生成的String对象地址存放在s9中.         * s10存储的是字符串池中"abcd"对应的地址.         * s9存储是堆中"abcd"对应地址         */        String s7 = "ab";        String s8 = "cd";        String s9 = s7 + s8;        String s10 = "abcd";        System.out.println("s9 == s10:"+(s9 == s10)); // false        /**         * 5.java编译器对String+基本类型/常量, 当成常量表达式直接求值优化         * 运行期两个string相加,会产生新的对象, 存在堆中         */        String s11 = "b";        String s12 = "a" + s11;        String s13 = "ab";        //因为s11是变量(被final修饰是常量),所以运行期才会被解析        System.out.println("s12 == s13:"+(s12 == s13) ); // false        final String s14 = "b";        String s15 = "a" + s14;        String s16 = "ab";        System.out.println("s15 == s16:"+(s15 == s16)); // true    }

面试题:
曾经一个面试题 :

public static void main(String[] args) {        String a = "hello";        String b = "hel" + "lo";        String c = "hel" + new String("lo");        final String d = "lo";        String e = "lo";        String f = "hel" + d;        String g = "hel" + e;        System.out.println(a == b); // true b是常量相加        System.out.println(a == c); // false new String会重新新建对象        System.out.println(a == f); // true d是常量(被final修饰)        System.out.println(a == g); // false e是变量不会编译期优化    }

3.以前疑惑

对于String a = “abc”, 我总在思考 a 到底是字符串常量还是变量 . 你说它是常量, 他却没有被final修饰, 如果说变量但是”abc”会被放在常量池中 .
最后别人一句话点醒了我, a 是变量, “abc”是常量 . 我以前老纠结在 a 上, 导致概念各种混乱 .
如果a要变成常量 , 需要被final修饰 , final String a = “abc” .

0 0