这里有新鲜出炉的 Java 并发编程示例,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
这篇文章主要介绍了详解 java 中继承关系类加载顺序问题的相关资料, 需要的朋友可以参考下
详解 java 中继承关系类加载顺序问题
实例代码:
- /**
- * Created by fei on 2017/5/31.
- */
- public class SonClass extends ParentClass {
- public SonClass() {
- System.out.println("SonClass's constructor");
- } {
- System.out.println("SonClass's block");
- }
- static {
- System.out.println("SonClass's static block ");
- }
- public static void main(String[] args) {
- System.out.println("------ main start ------ ");
- new SonClass();
- System.out.println("------ main end ------ ");
- }
- }
- class ParentClass {
- public ParentClass() {
- System.out.println("ParentClass's constructor");
- } {
- System.out.println("ParentClass's block");
- }
- static {
- System.out.println("ParentClass's static block ");
- }
- }
运行结果:
- ParentClass's static block
- SonClass's static block
- ------ main start ------
- ParentClass's block
- ParentClass's constructor
- SonClass's block
- SonClass's constructor
- ------ main end ------
根据运行结果,一目了然,在执行 main 方法中 new SonClass() 之前,就在类加载之后执行了类中 static 代码块。然后再进入 main 方法,执行 new 操作,当然显而易见,在执行 new 子类操作的时候,是要先进行其父类的构造,即先执行父类的构造代码块(代码中只用大括号包裹的那段代码)以及构造函数 ,然后再执行子类的构造代码块以及构造函数。
修改一下代码,再来看看运行的结果:
- /**
- * Created by fei on 2017/5/31.
- */
- public class SonClass extends ParentClass {
- ParentClass parentClass;
- public SonClass() {
- System.out.println("1");
- }
- public SonClass(String name) {
- System.out.println("2");
- this.name = name;
- parentClass = new ParentClass("FEI");
- }
- public static void main(String[] args) {
- System.out.println("------ main start ------ ");
- new SonClass("fei");
- System.out.println("------ main end ------ ");
- }
- }
- class ParentClass {
- String name;
- public ParentClass() {
- System.out.println("3");
- }
- public ParentClass(String name) {
- System.out.println("4");
- this.name = name;
- }
- }
运行的顺序是:
- ------ main start ------
- 3
- 2
- 4
- ------ main end ------
第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你 new 一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。
第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。
总之,一句话:子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。
还是两个类,我们再更改一下。
- /**
- * Created by fei on 2017/5/31.
- */
- public class SonClass extends ParentClass {
- private String name = "SonClass";
- public SonClass() {
- printName();
- }
- public void printName() {
- System.out.println("SonClass print name: " + name);
- }
- public static void main(String[] args) {
- new SonClass();
- }
- }
- class ParentClass {
- private String name = "ParentClass";
- public ParentClass() {
- //System.out.println(this.getClass());
- printName();
- }
- public void printName() {
- System.out.println("ParentClass print name: " + name);
- }
- }
看了上面的两个例子,最后这个例子就很容易被迷惑,可能有人会觉得运行结果是类似这样的:
- ParentClass print name: ParentClass
- SonClass print name: SonClass
或者是:
- ParentClass print name: SonClass
- SonClass print name: SonClass
但真正的结果是这样的:
- SonClass print name: null
- SonClass print name: SonClass
为什么会这样,其实只要打开代码中父类构造器中的这句注释,就很容易理解了:System.out.println(this.getClass())
结果是:
- class SonClass
没错,父类中的 this 引用是子类实例对象,所以在父类构造函数里调用的还是子类的 printName()方法。具体原因也并我能十分肯定,我个人浅见,是因为虽然我们调用了父类的构造方法,但是我们并没有实例化出父类的实例对象,所以 this 还是指向的是子类的引用。
来源: http://www.phperz.com/article/17/0821/338385.html