专栏首页国产程序员在java中String类为什么要设计成final?

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

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

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

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

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

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

/**
 * 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类起手前三行,是这样写的:

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指向堆区另一个地址

final int[] value={1,2,3}
int[] another={4,5,6};
value=another;    //编译器报错,final不可变

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

final int[] value={1,2,3};
value[2]=100;  //这时候数组里已经是{1,2,100}

当String为final类型时:

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模拟:

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"赋值。它们其实都指向同一个内存地址。

String one = "someString";
String two = "someString";

本文分享自微信公众号 - 国产程序员(Monday_lida),作者:看似无限透明的你

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-08-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java14新特性:增强 instanceOf 类型推断

    obj instanceof String已经为true,在后面的代码里,我们还是要清晰的定义一个新变量,并且要做类型强转换。

    一觉睡到小时候
  • SpringMVC之细说HandlerMapping

    客户端发送请求,web容器接受请求,如果请求与DispatcherServlet的请求映射路径(url-pattern)匹配,web容器将请求交给Dispatc...

    一觉睡到小时候
  • Java方法的精确度

    咋一看,传递给方法的参数是一个空的对象引用,因此,初看起来,该程序好像应该调用参数类型为Object 的重载版本,

    一觉睡到小时候
  • 使用java编程实现明文和密文之间的互转

    现在你就可以自定义key,增加难度,但是这个还是不安全,密钥还是可能被套取,所以加入当前时间,这样每次生成的密钥都不一样

    Erwin
  • 我说精通字符串,面试官竟然问我 Java 中的 String 有没有长度限制?

    String 是 Java 中很重要的一个数据类型,除了基本数据类型以外,String 是被使用的最广泛的了,但是,关于 String,其实还是有很多东西容易被...

    淡定的蜗牛
  • 我说我精通字符串,面试官竟然问我Java中的String有没有长度限制!?

    String是Java中很重要的一个数据类型,除了基本数据类型以外,String是被使用的最广泛的了,但是,关于String,其实还是有很多东西容易被忽略的。

    Java技术江湖
  • JVM系列之:String.intern和stringTable

    StringTable是什么?它和String.intern有什么关系呢?在字符串对象的创建过程中,StringTable有起到了什么作用呢?

    程序那些事
  • 聊聊nacos NamingProxy的getServiceList

    nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/naming/net/NamingProxy...

    codecraft
  • PC 微信扫码登陆

    网站应用微信登录是基于OAuth2.0协议标准构建的微信OAuth2.0授权登录系统。进一步了解OAuth2.0-----理解OAuth2.0 官方介绍资料

    Javen
  • 这样规范写代码,同事直呼“666”

    zhisheng

扫码关注云+社区

领取腾讯云代金券