您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    对话式情形剖析,String被Final修饰的真正缘由!一篇足矣
    时间:2019-07-15 21:02 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    对话式情形剖析,String被Final修饰的真正缘由!一篇足矣

    面试官:你好,能看得清下面这张图吗?

    对话式情形剖析,String被Final修饰的真正缘由!一篇足矣


    我:可以的。

    面试官:恩,好的。呃,你能不能说一说为什么String要用final修饰?

    我:final意味着不能被承袭或许被重写,String类用final修饰是Java的设计人员不希望客户端顺序员承袭String类,并有能够改写String类中的办法。运用String对象的最佳实际,应该是关联或许依赖,而不是承袭。

    面试官:恩,你还没有说到点儿上,能再展开谈谈吗?

    我:恩,好的。详细来说,String类被定义为final的主要是从两个方面来思索:安全和功用,也就是说,String被设计成final的,即思索到了安全性,也统筹了功用成绩。

    我们可以看到下面这张图中,出现了两个final。一个final是修饰了String类,而另一个final修饰了char数组。我们知道,String的本质实践上就是这个char数组,先来说一说 final char[] 的这个 final。

    用final修饰char数组的缘由,还需求从我们日常的实践开发中说起。

    在日常的实践开发中,开发者会用到少量的字符串对象,可以说我们无时无刻不在和字符串打交道。少量的字符串被随便的创立出来,这就触及到一个十分严重的成绩,即功用的开支,我们知道分配给Java虚拟机的内存是有限的,假设不加节制的创立字符串对象,那么弊端不言而喻:内存迅速被占满,顺序执行缓慢!!!于是Java的设计者采用了一种十分有效的处置办法,即:共享字符串。共享字符串对象的办法是将字符串对象寄存到虚拟机中的办法区外面的常量池里,不同的类,不同的办法,甚至是不同的线程,可以运用同一个字符串对象,而不需求再在内存中开拓新的内存空间,从而极大的降低了内存的消耗,也提升了顺序运转效率。

    因此,字符串共享是处置内存消耗以及庞大的功用开支的必然选择。但是到这里为止,还不能解释为什么这个char数组要用final修饰。用final修饰的缘由来自于另一个必需要思索的成绩:安全性。什么是安全性?这里的安全性,指的是线程安全性,这个很好了解,首先,我们曾经确定了一个大的前提:字符串要共享,否则内存将瞬间挤爆、功用将严重下降。

    但是共享的成绩在于:不同的线程有能够会修正这个共享对象。

    比如,thread_1正在循环一个List,每个元素和 “abc” 停止比较,同时thread_2也在运用这个 “abc” 对象,假设thread_2改动了这个共享字符串,结果会怎样?很清楚,thread_1 的结果将不可预测!!因此,处置共享变量安全性的最好的手腕,就是制止修正共享对象,于是字符串对象的这个char数组就必然要被 final 修饰了,由于 final 意味着制止改动。

    面试官:恩恩,没想到你的想法这么透彻!那么,这是char数组final的作用,那为什么还要给String类本身加一个final呢?

    我:恩,这也是另一个Java设计者需求思索的成绩。既然共享字符数组曾经确定是final的、不能改动的了,那为什么要给String也加一个final呢?缘由依然是功用和安全性两个方面。

    但是,此时需求思索的功用和安全性却和 final char[] 的final 不太一样了。

    首先,假设假定String可以被承袭,那么办法也可以被重写,这外面触及到一个C++中的概念,叫做:虚函数表。

    面试官:哦?你还懂C++?

    我: 是的。异样是面向对象的言语,Java和C++有着共通的中央。首先,虚函数是指:可以定义一个父类的指针, 其指向一个子类对象, 当经过父类的指针去调用函数时, 可以在运转时决议应该调用父类的函数还是子类的函数。虚函数是完成多态的基础。前面说了,假设String可以被承袭,那么势必就会有人经过创立String援用并指向String子类对象的方式,来运用子类的办法,比如像这样写:

    String aa = new SubString("abcd"); 

    aa.length(); 

    这看似没有什么成绩,但是成绩在于功用,前面提到了,在顺序开发进程中,字符串对象是十分常用的,上述代码在调用对象aa.length() 时,虚拟机就会去虚函数表中查找并判定终究是应该调用哪个子类的length()办法。在少量运用字符串对象的场景下,势必会降低顺序运转效率。

    其次又是安全性,这个安全性的解释为语义的安全性,面向对象的言语本身就要求要有明晰的语义和明白的表达。String的各个办法都围绕着一个char数组停止,一切办法的语义都是最直接、最有效的。重写String的办法意味着:不一样的语义或许错误的语义。这将直接招致String行为的不确定性,运用String对象的代码将会是不安全的代码。因此,Java设计者才会制止任何人承袭String类,主要是为了String对象的操作语义不被改动,确保运用String对象的代码是相对安全的。

    面试官:原来如此,没想到你的了解这么到位!年薪50万,明天就来下班吧!


    总结

    当面试官问道为什么 String 是final的时分,要答出两方面:第一就是final char value[] 的final ;第二就是 final class 的final。

    这两个final都要紧扣安全与功用两个方面阐述。

    1、final char value[] 的final 要抓住几个关键点是:value[]数组的final用于限制字符数组的修正。字符串将会被少量运用,从功用上思索迫使Java言语的设计者将 char[] 设计为共享的,又由于字符串是共享的再次迫使设计者思索到线程安全性,这才需求用final来修饰,避免并发场景下的行为不可预测。

    (责任编辑:admin)