前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在java中String类为什么要设计成final?

在java中String类为什么要设计成final?

作者头像
一觉睡到小时候
发布2019-07-02 17:00:33
9130
发布2019-07-02 17:00:33
举报
文章被收录于专栏:国产程序员国产程序员

String为什么被定义为final在面试中经常被问到。

首先,先得清楚 final 这个关键字。

final的出现就是为了为了不想改变,而不想改变的理由有两点:设计(安全)或者效率。

final 修饰的类是不被能继承的,所以 final 修饰的类是不能被篡改的。

了解了这一点,我们再看看源码

代码语言:javascript
复制
/**
 * The {@code String} class represents character strings. All
 * string literals in Java programs, such as {@code "abc"}, are
 * implemented as instances of this class.
 * <p>
 * Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. For example:
 *     String str = "abc";
 * is equivalent to:
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 */
 对应翻译:
/**
*字符串类表示字符串。所有
*在java程序中的字符串,如“ABC”,是
*实现为这个类的实例。
*
*字符串是常量,它们的值在它们之后不能更改
*创建。支持可变字符串字符串缓冲区。
*因为字符串对象是不可改变的,它们可以共享。

翻开JDK源码,java.lang.String类起手前三行,是这样写的:

代码语言:javascript
复制
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    /** String本质是个char数组. 而且用final关键字修饰.*/
    private final char value[];
    ...
    ...
}

String类的主力成员字段value是个char[ ]数组,而且是用final修饰的。final修饰的字段创建以后就不可改变。

数组变量只是stack上的一个引用,数组的本体结构在heap堆。String类里的value用final修饰,只是说stack里的这个叫value的引用地址不可变。没有说堆里array本身数据不可变。

value用final修饰,编译器不允许我把value指向堆区另一个地址

代码语言:javascript
复制
final int[] value={1,2,3}
int[] another={4,5,6};
value=another;    //编译器报错,final不可变

但如果我直接对数组元素动手

代码语言:javascript
复制
final int[] value={1,2,3};
value[2]=100;  //这时候数组里已经是{1,2,100}

当String为final类型时:

代码语言:javascript
复制
package test;

public class 为什么String要设计成不可变类 {

    public static void main(String[] args) {

        String a, b, c;
        a = "test";
        b = a;
        c = b;
        String processA = processA(a);
        String processB = processB(b);
        String processC = processC(c);
        System.out.println(processA);
        System.out.println(processB);
        System.out.println(processC);
    }

    static String processA(String str){
        return str + "A";
    }

    static String processB(String str){
        return str + "B";
    }

    static String processC(String str){
        return str + "C";
    }

}
//OUTPUT
// testA
//testB
//testC

当String设计成非final,我们用StringBuilder模拟:

代码语言:javascript
复制
package test;

public class 为什么String要设计成不可变类{

    public static void main(String[] args) {

        StringBuffer a, b, c;
        a = new StringBuffer("test");
        b = a;
        c = b;
        String processA = processA(a);
        String processB = processB(b);
        String processC = processC(c);
        System.out.println(processA);
        System.out.println(processB);
        System.out.println(processC);
    }

    static String processA(StringBuffer str){
        return str.append("A").toString();
    }

    static String processB(StringBuffer str){
        return str.append("B").toString();
    }

    static String processC(StringBuffer str){
        return str.append("C").toString();
    }

}
//OUTPUT
// testA
//testAB
//testABC

最后别忘了String另外一个字符串常量池的属性。像下面这样字符串one和two都用字面量"something"赋值。它们其实都指向同一个内存地址。

代码语言:javascript
复制
String one = "someString";
String two = "someString";
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 国产程序员 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档