}
// 子类不能重写父类的final方法,否则编译期异常
// ‘test()’ cannot override ‘test()’ in ‘extendsTest.Super’; overridden method is final
// @Override
// public void test(){
// System.out.println(“Base try to override Super final method”);
// }
}
思考题
===
1.Java的继承体系都是单继承吗?
不是。
Java的类的继承体系都是单继承。
但是
Java的接口的继承体系时多继承,即一个接口可以继承多个其他接口。
2.Java的类不是单继承吗,比如A继承B,但是B中并没有定义equals,toString等方法,为什么A类对象还是可以调用这些方法?
Java类的继承体系是单继承。即一个类只能由一个父类。
且继承发生后,子类可以继承父类的所有成员变量,成员方法,内部类,枚举类。
但是Java继承还有一个规则:
如果一个类没有显式继承其他类,则默认继承java.lang.Object类
举个例子
A extends B
B extends C
C extends D
D 没有显式继承任何其他类
分析:
由于D没有显式继承其他类,所以D默认继承Object类。所以D获得Object类的所有成员方法(equals,toString等)
而C继承了D,所以C也获得了(equals,toString)
而B继承C,所以B也获得了(equals,toString)
同理A最终也能获得(equals,toString)
总结:Java中类的继承是单继承,只能说明一个类只能由一个直接父类,但是可以由多个间接父类。
3.子类为什么不能继承父类的构造器和初始化块?
我们知道构造器的名字必须和类名相同。
而子类继承自父类的成员的名字不会改变。所以构造器不能被继承,因为继承自父类的构造器和子类类名冲突。
另外,初始化块在本质上是属于构造器的一部分。在代码编译后,初始化块就会消失,初始化块中的代码会融入到构造器中,且在原先构造器执行体代码前。
4.子类构造器中使用super关键字可以调用父类构造器,会导致产生父类对象吗?
不会。
在子类构造器中使用super调用父类构造器,只是为了给子类对象中(继承自父类的实例变量)完成初始化。不会产生父类对象。
5.子类不会继承父类的构造器和初始化块,我们知道构造器可以用super调用,那么父类的初始化块,子类怎么调用?
首先我们需要知道初始化块是无法被外界调用的,它只在类加载时(静态初始化块),或创建对象时(实例初始化块)执行一次。
另外我们知道 构造器执行前,总会先执行实例初始化块。
所以当我们用super调用父类构造器时,父类构造器会默认先调用实例初始化块。
6.子类是否可以继承父类final修饰的实例变量,和实例方法?
public class Main{
public static void main(String[] args){
Base b = new Base();
b.test();
System.out.println(b.num);
}
}
class Super{
final int num = 10;
final void test(){
System.out.println(“Super final method”);
}
}
class Base extends Super{}
首先运行上面的程序发现,正常运行,结果是
Super final method
10
所以子类可以继承父类的final方法和变量。
对于final关键字的作用:
1.被final修饰的类无法派生子类
2.被final修饰的变量,不能改变指向
3.被final修饰的方法,不能被子类重写。
所以子类只是不能重写父类final方法,也不能继承自父类的final变量的指向
7.子类是否可以继承父类的私有成员?
更具继承定义来看:
子类可以继承父类(除构造器,初始化块)的所有成员。
没有提到私有成员,所以子类继承了父类的私有成员的。只是子类无法访问继承自父类的私有成员而已。
这里可以将继承分为两种:
显式继承:可以访问从父类继承到的成员。
隐式继承:无法访问从父类继承到的成员。
8.子类可以将父类的静态方法重写为实例方法吗?
不可以
方法重写有一个规则:
父类实例方法只能被子类实例方法重写。
对于父类静态方法,存不存在重写规则,尚存争议。更不要说被子类实例方法重写。
另外,父类静态方法属于父类本身,在内存中只有一份。即使被子类继承,子类也不会像为(继承自父类的实例变量)单独开辟一个内存存储,而是会直接访问父类的静态方法。
9.当子类定义了和父类相同的实例变量时,父类的实例变量会被覆盖吗?
不会。子类只会隐藏继承自父类的同名实例变量。
因为子类继承父类后,创建子类对象时,会开辟两块内存空间:
一块用于存储子类本身的实例变量
一块用于存储继承自父类的实例变量
所以在内存上来看,子类实例变量和继承自父类的实例变量不会发生覆盖现象。
10.子类从父类继承的方法是否可以操作子类自定义的变量?请思考下面代码运行结果(好玩的题目,让我认识到自己对继承的了解还不够深入)
public class Main{
public static void main(String[] args){
A a = new A();
a.printOut();// A.i相加 A:1
B b = new B();
b.printOut();// B.i相加 A:0
b.show();// 2
a = b;
a.printOut();// B.i相加 A:0
}
}
class A {
int i = 0;
public void doAdd(){
i++;
System.out.println(“A.i相加”);
}
public void printOut(){
this.doAdd();
System.out.println(“A:”+i);
}
}
class B extends A {
public int i = 0;
public void doAdd(){
i+=2;
System.out.println(“B.i相加”);
}
public void show(){
System.out.println(i);
}
}
结论:子类继承的方法,只能操作子类继承的成员变量。
11.super关键字与this关键字的区别是什么,它们之间是什么关系?
主要是用途上的区别
this的用途
1.在实例方法中 代表 调用该实例方法的对象。可以用来调用本类其他实例方法。
2.在构造器中 代表 当前创建对象。 可以用来区别同名变量是形参还是对象的实例变量。
3.在构造器中 调用 其他重载的构造器。
super的用途
1.作为对象,限定该对象调用它从父类继承得到的实例变量,实例方法
2.作为构造器,限定该构造器初始化的是该对象从父类继承得到的实例变量,而不是自己的实例变量
当this和super在构造器中使用时,他们不能同时出现。
因为它们都要定义在构造器的第一行。
12.为什么说子类构造器总会调用一次父类构造器?
如果子类中只定义了一个构造器,则有三种情况:
class Base{
Base(){
// 什么都不写,系统自动隐式调用父类无参构造器
//super();// super()是显式调用父类无参构造器
//super(12);// super(12)是显式调用父类有参构造器
}
}
显然,此时肯定会调用父类构造器
如果子类中定义了多个重载构造器:
那么如果多个重载构造器中没有使用this互相引用,那么每个构造器都是默认调用super,或者显式调用super
最后
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等
前端视频资料:
写,系统自动隐式调用父类无参构造器
//super();// super()是显式调用父类无参构造器
//super(12);// super(12)是显式调用父类有参构造器
}
}
显然,此时肯定会调用父类构造器
如果子类中定义了多个重载构造器:
那么如果多个重载构造器中没有使用this互相引用,那么每个构造器都是默认调用super,或者显式调用super
最后
本人分享一下这次字节跳动、美团、头条等大厂的面试真题涉及到的知识点,以及我个人的学习方法、学习路线等,当然也整理了一些学习文档资料出来是给大家的。知识点涉及比较全面,包括但不限于前端基础,HTML,CSS,JavaScript,Vue,ES6,HTTP,浏览器,算法等等
[外链图片转存中…(img-Sc1HIJ50-1714772186078)]
前端视频资料: