前言

今天来总结下Java中基础相关的一些内容,包含this与super关键字、静态方法等内容。

this与super关键字

代码实例

父类:

1
2
3
4
5
6
7
8
9
package com.example.model.auto;

public class Father {

protected void doSomething(){
System.out.println("Father's doSomething");
doSomething();
}
}

父类中有一个doSomething()方法,里面递归调用了doSomething()方法。

子类:

1
2
3
4
5
6
7
8
9
10
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方法:

1
2
3
4
5
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”。

按照分析,最后的结果应该是这样的:

1
2
3
4
5
6
7
8
Son's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
Father's doSomething
......

验证

实战一下,看看自己的分析对不对,结果如下:

结果和我们想的完全不一样。

思考

问题出在第三步,Father类中doSomething方法调用doSomething方法的时候调用的不是Father类中的方法,而是Son类中已经重写了的方法:

在Father类的doSomething()方法中调用通过this.doSomething()进行调用,结果也是一样:

简单分析了下整个的调用过程,如下图:

总结

总结:在运行时实际的类是Son类,然后所有通过this关键字调用的,都是先查找本类,本类没有找到的,再去查找父类。this在单独使用时可以指代当前对象。

关于thissuper关键字的区别和用法总结如下:

thissuper
基本概念查找本类实例属性和方法由子类访问父类中的实例属性和方法
查找范围先找本类,没有则找父类直接查找父类
特异功能单独使用时,表示当前对象在子类覆写(override)父类的方法时,访问父类同名方法
共同点1,都是关键字,起指代作用2,在构造方法中都必须出现在第一行;
由于this和super都是在实例化阶段调用,所以不能在静态方法和静态代码块内使用this和super关键字

构造方法和静态方法

介绍

构造方法是方法名与类名相同的特殊方法,在新建对象时调用,可以通过不同的构造方法实现不同方式的对象初始化。

类中的static{}代码被称为类的静态代码块,在类初始化时执行,优先级很高。

代码实例

下面通过一个例子看一下父子类静态代码块和构造方法的执行顺序:

父类:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.model.auto;

class Father {

static {
System.out.println("Father 静态代码块");
}

public Father(){
System.out.println("Father 构造方法");
}

}

子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.model.auto;


class Son extends Father {

static {
System.out.println("Son 静态代码块");
}

Son(){
System.out.println("Son 构造方法");
}
}

写个main方法,新建个Son对象测试下:

1
2
3
  public static void main(String[] args) {
new Son();
}

执行结果:

再测试一个main方法,创建两个Son对象:

1
2
3
4
public static void main(String[] args) {
new Son();
new Son();
}

可以看到,在创建类对象时,先执行父类和子类的静态代码块,然后再执行父类和子类的构造方法。并不是执行完父类的静态代码块和构造方法后,再去执行子类。静态代码块只执行一次,在第二次对象实例化时,不会执行。

总结

本文主要是this与super关键字、构造方法与静态方法的执行顺序两个层面来看Java中代码的执行。