前言
今天来总结下Java中基础相关的一些内容,包含this与super关键字、静态方法等内容。
this与super关键字
代码实例
父类:
package com.example.model.auto;
public class Father {
protected void doSomething(){
System.out.println("Father's doSomething");
doSomething();
}
}
父类中有一个doSomething()方法,里面递归调用了doSomething()方法。
子类:
package com.example.model.auto;
public class Son extends Father {
@Override
public void doSomething() {
System.out.println("Son's doSomething");
super.doSomething();
}
}
继承父类,并重写父类的doSomething()方法。doSomething()方法中通过super.doSomething()调用了父类的doSomething()方法。
main方法:
public static void main(String[] args) {
Father father=new Son();
father.doSomething();
}
new一个子类对象,用父类引用指向子类对象。
分析
我先分析下这个执行结果,由于Java的动态绑定机制,在运行时才知道执行的是子类的doSomething()方法,如下图:
第一步,应该先打印出 “Son’s doSomething”。然后执行super.doSomething();
,调用的是Father的doSomething方法,如下:
第二步,此时应该打印出“Father’s doSomething”。
然后继续执行后面的doSomething()方法,此时应该是递归调用自己:
第三步,应该是一直循环打印结果“Father’s doSomething”。
按照分析,最后的结果应该是这样的:
Son's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
......
验证
实战一下,看看自己的分析对不对,结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hrBOuSyH-1640702374700)(https://img.liuyj.top/image-20210701112123842.png)]
结果和我们想的完全不一样。
思考
问题出在第三步,Father类中doSomething方法调用doSomething方法的时候调用的不是Father类中的方法,而是Son类中已经重写了的方法:
在Father类的doSomething()方法中调用通过this.doSomething()进行调用,结果也是一样:
简单分析了下整个的调用过程,如下图:
总结
总结:在运行时实际的类是Son类,然后所有通过this关键字调用的,都是先查找本类,本类没有找到的,再去查找父类。this在单独使用时可以指代当前对象。
关于this和super关键字的区别和用法总结如下:
this | super | |
---|---|---|
基本概念 | 查找本类实例属性和方法 | 由子类访问父类中的实例属性和方法 |
查找范围 | 先找本类,没有则找父类 | 直接查找父类 |
特异功能 | 单独使用时,表示当前对象 | 在子类覆写(override)父类的方法时,访问父类同名方法 |
共同点 | 1,都是关键字,起指代作用 | 2,在构造方法中都必须出现在第一行; 由于this和super都是在实例化阶段调用,所以不能在静态方法和静态代码块内使用this和super关键字 |
构造方法和静态方法
介绍
构造方法是方法名与类名相同的特殊方法,在新建对象时调用,可以通过不同的构造方法实现不同方式的对象初始化。
类中的static{}代码被称为类的静态代码块,在类初始化时执行,优先级很高。
代码实例
下面通过一个例子看一下父子类静态代码块和构造方法的执行顺序:
父类:
package com.example.model.auto;
class Father {
static {
System.out.println("Father 静态代码块");
}
public Father(){
System.out.println("Father 构造方法");
}
}
子类:
package com.example.model.auto;
class Son extends Father {
static {
System.out.println("Son 静态代码块");
}
Son(){
System.out.println("Son 构造方法");
}
}
写个main方法,新建个Son对象测试下:
public static void main(String[] args) {
new Son();
}
执行结果:
再测试一个main方法,创建两个Son对象:
public static void main(String[] args) {
new Son();
new Son();
}
可以看到,在创建类对象时,先执行父类和子类的静态代码块,然后再执行父类和子类的构造方法。并不是执行完父类的静态代码块和构造方法后,再去执行子类。静态代码块只执行一次,在第二次对象实例化时,不会执行。
总结
本文主要是this与super关键字、构造方法与静态方法的执行顺序两个层面来看Java中代码的执行。