继承
- 基础
- 1. 继承的特点
- 2. super关键字
- 3. 继承中变量访问特点(就近原则)
- 4. 继承中成员方法访问特点
- 5. 继承中构造访问特点
- 为什么子类中所有构造方法默认都会访问父类无参构造方法。
- 如果父类中没有无参构造
- 6. 重写
- 概述
- 应用
- 注意事项
- 方法重写和重载有什么区别?
- 7. 静态代码块、构造代码块,构造方法的执行顺序
- 面试题
- 面试题1:变量访问原则 - 就近原则
- 面试题2:一个类的静态代码块,构造代码块,构造方法的执行流程
- 面试题3
- 面试题4:一个类同时继承了一个类和一个接口,如果类和接口内有相同的方法,调用优先级
基础
1. 继承的特点
Java只支持单继承,不支持多继承。
2. super关键字
super是一个关键字,代表父类的存储空间标识。(可以理解为父亲的引用)
super和this的用法相似。
this代表对象的引用(谁调用就代表谁);
super代表当前子类对父类的引用。
3. 继承中变量访问特点(就近原则)
在子类方法中访问一个变量
子类局部范围查找
子类成员范围查找
父类成员范围查找
如果都没有就报错(不考虑父亲的父亲)
4. 继承中成员方法访问特点
子类成员范围查找
父类成员范围查找
如果都没有就报错(不考虑父亲的父亲)
5. 继承中构造访问特点
子类中所有构造方法默认都会访问父类无参构造方法。
为什么子类中所有构造方法默认都会访问父类无参构造方法。
因为子类会继承父类中的数据,可能还会使用父类中的数据,因此,子类初始化前,会先初始化父类。
如果父类中没有无参构造
可以通过super关键字显式调用父类有参构造,或父类添加无参构造
6. 重写
概述
子类中出现与父类一模一样的方法时(除了权限修饰符,权限修饰符大于等于不包括private,返回值类型,方法名和参数列表相同),会出现覆盖操作,称为重写
应用
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,既沿袭了父类的功能,又定义了子类特有的内容。
注意事项
私有方法不能被重写(父类私有成员子类不能继承)
子类方法权限修饰符大于等于父类(public>默认>私有)
方法重写和重载有什么区别?
方法的重写用在子类方法与父类方法一模一样时,除权限修饰符,返回值类型,方法名和参数列表都是相同的。
重载用在同一个类中各方法方法名相同,参数列表不同(与返回值类型没有关系)的情况。
7. 静态代码块、构造代码块,构造方法的执行顺序
父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法
面试题
面试题1:变量访问原则 - 就近原则
class Fu {
public int num = 10;
public Fu() {
System.out.println("fu");
}
}
class Zi extends Fu {
public int num = 20;
public Zi() {
System.out.println("zi");
}
public void show() {
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class ExtendsTest {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
fu
zi
30
20
10
知识点:子类的所有构造方法执行前默认先执行父类的无参构造方法
知识点:访问成员变量的原则:就近原则(子类局部>子类成员>父类成员)。
this和super指向:
this - 访问本类的成员
super - 访问父类的成员(可以理解为的)
面试题2:一个类的静态代码块,构造代码块,构造方法的执行流程
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
class ExtendsTest2 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
一个类的静态代码块,构造代码块,构造方法的执行流程
静态代码块 > 构造代码块 > 构造方法
父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法
解析
静态的内容是随着类的加载而加载:静态代码块的内容会优先执行。
构造代码块:在类中方法外出现(即在类中的成员位置),可以把多个构造方法方法中相同的代码存放到一起,用于对对象进行初始化。每次调用构造方法都执行,并且在构造方法前执行。
子类的所有的构造方法默认都会去访问父类的无参构造方法。
面试题3
class X {
//成员变量(引用类型)
Y b = new Y();
//无参构造方法
X() {
System.out.print("X");
}
}
class Y {
//无参构造方法
Y() {
System.out.print("Y");
}
}
public class Z extends X {
//成员变量(引用类型)
Y y = new Y();
//无参构造方法
Z() {
//super(); //它仅仅表示要先初始化父类数据,再初始化子类数据。
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
YXYZ
知识点:一个类的初始化过程
Student t = new Student();
创建一个对象都在内存中做了什么事情?
- 先将硬盘上指定位置的Student.class文件加载进内存。
- 执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量t。
- 在堆内存中开辟一个实体空间,分配了一个内存首地址值。new
- 在该实体空间中进行属性的空间分配,并进行了默认初始化。
- 对空间中的属性进行显示初始化。
- 进行实体的构造代码块初始化。
- 调用该实体对应的构造函数,进行构造函数初始化。
- 将首地址赋值给t,t变量就引用了该实体。(指向了该对象)
知识点:子父类的初始化过程
先进行父类初始化,然后进行子类初始化。
面试题4:一个类同时继承了一个类和一个接口,如果类和接口内有相同的方法,调用优先级
public interface A {
default void show(){
System.out.println("接口的方法");
}
}
public class B {
public void show(){
System.out.println("优先调用类的方法");
}
}
public class Test extends B implements A{
public static void main(String[] args) {
Test t = new Test();
t.show(); //调用类的方法
}
}
如果一个类同时继承了一个类和一个接口,如果类和接口内有相同的方法,那么创建对象调用的时候,会优先使用类的方法。如果子类重写,使用子类的方法
来源:https://www.runoob.com/w3cnote/java-extends.html
面试题来源:https://www.cnblogs.com/chenmingjun/p/8449506.html
一个类的初始化过程:https://blog.csdn.net/weixin_42638178/article/details/115805522