String类可以被继承吗?我们来聊聊final关键字!

String在java基础知识中绝对是个重点知识,关于String的一些问题也是非常的多,而且牵涉到内存等高级知识,在面试中也是经常被考察的一个点,那么我们今天就来一起讨论下这个String类是否可以被继承呢?以及为什么呢?其中我们会谈到一个非常重要的知识点,那就是final关键字了,下面开始吧!

庆哥: 小白,你对String类的掌握如何呢?

小白: String啊,了解的应该比较基础,关于字符串常量池应该是String中比较重要的一个知识点,理解字符串常量池就可以解决String相关的一些问题了,比如经常考察的创建几个对象的问题!

庆哥: 可以,你这块记得还可以,那么我问你一个关于String相关的问题,请听题,请问String类是否可以被继承呢?

小白: ???

庆哥: 还三个问号,怎么?是不是不知道啊?

小白: 实不相瞒,我还真不知道,听到这个问题,我发现我脑子一片空白,没有任何可以调取的信息,这说明我对这个问题是真的不理解啊,还请庆哥指教啊!

String类是否可以被继承?

庆哥: 那我们就一起来看看这个问题,首先我们要知道,如果你要判断一个类是否可以被继承的话,你要知道这个类是如何被定义的,所以我们先来看看这个String类是如何被定义的

以上就是这个String类的定义方式,我们可以明显的看到一个final修饰符!

小白: 哦哦,我知道了,那么这个String类是不可以被继承的。因为被final修饰的类是不可以被继承的。

庆哥: 可以啊,这么快就get到点啦,那你知道为什么吗?

小白: 当看到被final修饰,我脑海中立马就产生了不可以被继承的想法,但是具体的原因我却又说不出来,我发现我对这个final修饰符不是很理解!

庆哥: 是的,理解这个我们需要先来了解下final这个关键字,那你知道final可以修饰什么吗?

小白: Google ing...

哦哦,我知道了,这个final可以修饰类,方法和成员变量,感情一个类中的东西都可以被它修饰啊。

庆哥: 是的,这个final可以用来修饰

  1. 成员变量
  2. 方法

那么接下来我们就来说一下这三个被final修饰有什么作用,首先我们就来看这个修饰类

final修饰类

我们先来写一个被final修饰的类

通过这个例子我们可以看到,被final修饰的类并不可以被继承,所以到这里我们就能知道String类是不能被继承的。

小白: 哦哦,这下知道了,被final修饰的类是不能被继承的,感觉被final修饰像是被加上一把锁一样,被禁锢了一样。

庆哥: 是的,被final修饰的类就不能被其他类继承了,所以在设计类的时候如果真的是不想这个类被其他类继承或者考虑一些安全因素,否则尽量不要把类设计成final的。

final修饰成员变量

那么,你知道final修饰成员变量有什么作用吗?

小白: 这个我好想还真知道,因为这个在平时的编码过程中有用到过,应该是被final修饰的成员变量是不可以改变的,也就是固定下来,是一个常量值了。

庆哥: 对的,确实是这样,对于变量我们知道分为基础数据类型和引用数据类型,我们还是来看一个例子吧!

在这个例子当中我们发现被final修饰的基础数据类型和引用数据类型都是不能再次赋值的,这就说明被final修饰的变量是不可变的。

final修饰方法

接下来我们就来看看这个被final修饰的方法又是怎样的?

小白: 这个让我猜猜,被final修饰的方法是不是也不能被重载覆盖啊,或者不能被调用?

庆哥: 这个嘛....我们还是一起来看看吧,小白,你读过《java编程思想》这本书吗?

小白: 这本书可是经典啊,不过,实在是有点难啃啊。

庆哥: 哈哈。经典当然难啃啦,在这本书中有这样的描述

使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。

这句话什么意思呢?也就是说,如果你不想方法在子类中被重写,你就把这个方法设置成final,我们还是来看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
class Test1{
public void show(String s){
System.out.println("传进来的字符串是:"+s);
 
}
}
class Test2 extends Test1{
 
@Override
public void show(String s) {
System.out.println(s+"是被传进来的字符串!");
}
}

在这个例子中Test2继承了Test1并且覆盖了Test1的show方法,但是现在如果我不想这个方法被覆盖的话该怎么做呢?

也就是当方法被final修饰之后就不可以被覆盖了。

小白: 哦,我知道了,方法被final修饰之后不可以被子类覆盖,那么这个被final修饰的方法是否还可以正常调用以及可以重载吗?

庆哥: 可不可以我们写一个例子就知道了,看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {
public static void main(String[] args) {
new Test1().show();
}
}
 
class Test1{
 
public final void show(String s){
 
System.out.println("传进来的字符串是:"+s);
 
}
public void show(){
System.out.println("啥玩意也没有传进来!");
 
}
 
}

看输出结果

小白: 知道了,被final修饰的方法可以总结如下几点

  1. 在子类中不能被覆盖了
  2. 可以实现重载
  3. 依旧可以正常调用

庆哥: 可以的,总结的不错,关于final的基本用法我们讨论的差不多了,看你的总结觉得你也掌握了,下面我们就来说点高级的,再问你一个问题,你知道final修饰的成员变量和普通变量有什么区别吗?

比如这俩

 final String b = "hello";        String c = "hello";

小白: 这个,不就是b不可被修改,而c可以被修改嘛

庆哥: 那你看下面的代码输出结果是什么

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Test {
public static void main(String[] args) {
String a = "hello1";
final String b = "hello";
String c = "hello";
String d = b + 1;
String e = c + 1;
 
System.out.println(a == d);
System.out.println(a == e);
 
}
}

小白: 这个?有点迷啊,不应该都是true吗?

庆哥: 实际的答案是

小白: 咦,怎么第二个输出结果是false呢?这个就有点不理解了,e的最终值不也是“hello1”吗,为什么会是false呢?

final变量和普通变量的区别

庆哥: 这就牵涉到final变量和普通变量的区别了,这里的b是被final修饰的成员变量,所以当用到b的时候可以直接替换成b的值,也就是说这里的

String d = b + 1;

其实直接就等价于

String d = "hello" + 1;

这样d的值也就是“hello1”,就像你说的e的值也是“hello1”啊,但是这里不同的是什么呢?

对于d这种在编译期就可以确定下来的值,也就是说在编译阶段已经确定d就是字符串“hello1”,那么这个值就会被放到字符串常量池中,但是对于e就不一样了,因为在编译阶段c是一个变量,也就是说在编译阶段并不能确定e的值,必须等到运行时才能确定e的值是“hello1”,但是这个时候这个值因为不是在编译阶段确定下来的就不会被放到字符串常量池中,a和e的引用是不同的,自然就是false!

小白: 看来在这里我有两个知识点不是很清楚

  1. 对于被final修饰的变量,在用的时候是可以直接替换的,因为其本身是固定不可变的
  2. 只有在编译阶段确定下来的字符串才是会被放到字符串常量池中的

庆哥: 我发现现在你的总结能力日益增强啊!很强势!

小白: 庆哥,我突然想到还有一个关键字叫做static,好像表示静态的,想到这个,突然感觉有点迷,这两个有啥区别啊?

final和static

庆哥: 还记得我们一般怎样定义静态常量吗?

是不是这样

static final String NAME = "Java从0到1";

这里要记住的就是

  1. static同来表示唯一,独此一份,也即是静态
  2. final用来表示不可变

这两者一结合不就是静态常量嘛,下面举一个随机数的例子,特别能说明这个问题,你看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
public static void main(String[] args) {
 
Test1 one = new Test1();
Test1 two = new Test1();
 
System.out.println(one.a);
System.out.println(one.b);
 
System.out.println(two.a);
System.out.println(two.b);
 
 
}
}
 
class Test1{
 
final double a = Math.random();
static double b = Math.random();
 
}

输出结果为

你会发现,b的值始终都是一样的!

小白: 哦哦,这下知道了,那static修饰的变量可以被改变吗?

庆哥: 这个我们再测试下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {    public static void main(String[] args) {
 
Test1 one = new Test1();
Test1 two = new Test1();
 
Test1.b = 0.2;
 
System.out.println(one.a);
System.out.println(one.b);
 
System.out.println(two.a);
System.out.println(two.b);
 
 
}
}
 
class Test1{
 
final double a = Math.random(); static double b = Math.random();
 
}

看输出结果

我想不用多说了吧!

小白: 今天真的是让我学到好多知识啊,真是受益匪浅,感谢庆哥!

庆哥: 那你知道String类为什么不可以继承了吗?

小白: 必须知道啊,面试也不怕被问到了!

String类可以被继承吗?我们来聊聊final关键字!的更多相关文章

  1. Java中的String类能否被继承?为什么?

    不能被继承,因为String类有final修饰符,而final修饰的类是不能被继承的. Java对String类的定义: public final class String implements ja ...

  2. Java中是否可以继承String类,为什么

    Java中,是否可以继承String类?为什么? 答案: 不可以,因为String类有final修饰符,而final修饰的类是不能被继承的,实现细节不允许改变. public final class ...

  3. String类无子类

    1. 关于final修饰符 参考文章: 浅析Java中的final关键字 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量 ...

  4. Java基础——数组应用之字符串String类

    字符串String的使用 Java字符串就是Unicode字符序列,例如串“Java”就是4个Unicode字符J,a,v,a组成的. Java中没有内置的字符串类型,而是在标准Java类库中提供了一 ...

  5. java中String类、StringBuilder类和StringBuffer类详解

    本位转载自http://www.cnblogs.com/dolphin0520/p/3778589.html  版权声明如下: 作者:海子 出处:http://www.cnblogs.com/dolp ...

  6. 跟着刚哥梳理java知识点——深入理解String类(九)

    一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class String implements java.io.Ser ...

  7. java里String类为何被设计为final

    前些天面试遇到一个非常难的关于String的问题,"String为何被设计为不可变的"?类似的问题也有"String为何被设计为final?"个人认为还是前面一 ...

  8. 深入理解Java String类(综合)

    在Java语言了中,所有类似“ABC”的字面值,都是String类的实例:String类位于java.lang包下,是Java语言的核心类,提供了字符串的比较.查找.截取.大小写转换等操作:Java语 ...

  9. String类——StringBuilder类的源码及内存分析(java)

    相同:底层均采用字符数组value来保存字符串 区别:String类的value数组有final 修饰,指向不可改,同时private 未提供修改value数组的方法.StringBuilder类的v ...

随机推荐

  1. python socket 的理解(1)

    前言 socket的用法简单,但里面的概念有点模糊,记录自己本人的一点理解. socket层结构图 注意,从此图中看出socket处于tcp和应用层之间.那么它代表啥意思呢?简明的说,数据的传输都是底 ...

  2. AngularJs双向绑定

    模型数据(Data) 模型是从AngularJS作用域对象的属性引申的.模型中的数据可能是Javascript对象.数组或基本类型,这都不重要,重要的是,他们都属于AngularJS作用域对象. An ...

  3. css: IE没法调整那些使用px作为单位的字体大小

    <style type="text/css"> h1{font-size:40px;} h3{font-size:30px;} p{font-size:14xp;} & ...

  4. ivew 【provide/inject] 页面刷新实现reload

    1.App.vue <template> <div id="app"> <router-view v-if="isRouterAlive&q ...

  5. 如何改变string中的字符值?

    string本身是不可变的,因此要改变string中字符,需要如下操作: str := “hello world” s := []byte(str) s[] = ‘o’ str = string(s) ...

  6. controllerweb.xml

    <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://w ...

  7. IDEA使用Maven的第一个测试

    创建完成后,点击这个按钮.进行配置. 选择第二个就行了. 然后选择这个去配置tomcat.

  8. sql判断中文、数字、英文

    IF OBJECT_ID('DBO.GET_NUMBER2') IS NOT NULL DROP FUNCTION DBO.GET_NUMBER2 GO )) ) AS BEGIN BEGIN ,'' ...

  9. NOIP 历年试题大致考点总结

    总的来说,水平还不够-- 要努力了! NOIP2012 D1T1 模拟, 字符串 D1T2 贪心, 数学 (推导贪心策略), 高精度 D1T3 unsolved 开车旅行 倍增 D2T1 解线性模方程 ...

  10. [CSP-S模拟测试]:y(DP+bitset)

    题目背景 $\frac{1}{4}$遇到了一道水题,叕完全不会做,于是去请教小$D$.小$D$懒得理$\frac{1}{4}$,直接就离开了.于是,$\frac{1}{4}$只好来问你,这道题是这样的 ...