摘要:因而,我们可以得出两个结论在实例化子类对象时,会执行父类中所有未加载的构造代码块和与子类相同的构造器。
导读
今天在做公司的项目,即统计实例化对象的存活个数,例如以下的代码
package com.zbystudy; /** * Created By zby on 14:27 2019/4/12 */ public class StaticFiled { public static int count = 0; private final int objCount = count++; public void printObjCount() { System.out.println("生成对象的个数为: " + objCount); } public static void main(String[] args) { for (int i = 0; i < 5; i++) { new StaticFiled().printObjCount(); } } }
输出如图所示:
在静态代码块中加法但是,我如果把代码修改成这样的:
public class StaticFiled { public static int count = 0; static { count++; } private final int objCount = count; 。。。。。。 }
你会发现,其只输出1,为什么会这样呢?会在下文讲解。
在构造代码块中加法我们再把代码修改成这样的,结果又会不一样:
public class StaticFiled { public static int count = 0; { count++; } private final int objCount = count; 。。。。。。 }
其输出结果是这样的:
你会发现,其跳过了0,而直接从1输出,哈哈,很奇怪,对吧?我也觉着很奇怪,不过,会在下文作详细介绍。
概念 构造器 概念假想我们没有构造器,但是我们还需要创建对象。因为,java是通过消息来请求其他对象。要想请求对象,势必向该对象发送一条消息,换句话说,可以把消息当做某个特定对象的方法的调用。因而,对象还是很重要的。如果我们手动去写一个方法,即初始化创建对象的方法,这势必会非常繁琐的。
因而,我们就想到了java自带的构造器,其就是为了初始化对象的。
构造代码块 概念定义在类的成员位置上,使用"{}"括起来的代码。构造代码块会在每次类被调用,或者被实例化时就会被执行。其优于用以实例化对象的构造器,如代码所示:
/** * Created By zby on 16:49 2019/4/12 */ public class Child{ private String name; public Child(String name) { super(name); this.name = name; } public Child(){ System.out.println("子类Child类的构造器"); } { System.out.println("子类Child类的 第一个 构造代码块"); } { System.out.println("子类Child类的 第二个 构造代码块"); } public static void main(String[] args) { new Child(); } }
其输出结果如图所示:
你会发现,程序先执行构造代码块,然后再执行构造器,也就是说,构造代码块的优先级比构造器的优先级高。
这也解决了我们上面的问题,为什么程序的输出会跳过0,直接从1开始输出呢?因为,我们首次实例化StaticFiled对象之前,构造代码块就已执行了一遍,此时的count是1,而不是0了。
同时,你也会发现,构造代码块的执行本身也是有先后顺序的,先写的先输出,后写的后输出。
父类中的构造代码块但是,如果父类中有构造代码块,子类输出又是什么样的呢?这样,我们定义一个父类,如代码所示:
public class Parent { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public Parent() { System.out.println("父类Parent类的构造器"); } { System.out.println("父类Parent类的 第一个 构造代码块"); } { System.out.println("父类Parent类的 第一个 构造代码块"); } }
我们再次执行Child类,观察此时的输出结果:
你会神奇的发现,首先输出父类的构造代码块和构造器,再次输出子类的构造代码块和构造器。
因而,我们可以得出两个结论:
在实例化子类对象时,会执行父类中所有未加载的构造代码块和与子类相同的构造器。
与子类相同的构造器是什么意思?也就是说,如果我们把Child类中main方法,修改为这样的: public static void main(String[] args){new Child("hhhh");},其输出结果是这样的:
父级和子类构造代码块和构造器之间的优先级:父级构造代码块 --》 父级构造器 --》 子类构造代码块 --》 子类构造器
静态代码块 概念静态代码块只执行一次,是在某个特定类第一次创建对象的时候执行,此后不再执行该静态代码块,如代码所示:
/** * Created By zby on 16:49 2019/4/12 */ public class Child extends Parent { private String name; public Child() { // System.out.println("子类Child类的构造器"); } static { System.out.println("子类Child类的静态代码块"); } public static void main(String[] args) { for (int i=0;i<10;i++){ new Child(); } } }
我们创建了10个子类对象,但只输出一次静态代码块中的数据,结果如图所示:
这也解决了上面的问题,为什么我们在静态代码块中执行这个指令: static {count++;} ,其输出结果始终是 1 的原因了。父类静态代码块
但是如果父类中存在静态代码块,子类的输出又是什么样的呢?
在Parent类中添加代码: static {System.out.println("父类Parent类的静态代码块");}
在Child类中添加代码: static {System.out.println("子类Child类的静态代码块");}
我们执行子类的代码,得到的截图:
由上图,我们得出了结论:
首先执行父类中的静态代码块,再执行子类的静态代码块。三者综合应用
父类中存在静态代码块、构造代码块、构造器,子类中也存在静态代码块、构造代码块、构造器,那么,输出结果是什么样的呢?
输出结果如图说示:
我们得出了这个结论三者的优先级:
父类静态代码块 --》 子类静态代码块 --》父类构造代码块 --》 父类的构造器 --》子类构造代码块 --》子类构造器总结
我们只有明白了父类静态代码块、子类静态代码块、父类构造代码块、父类的构造器、子类构造代码块、子类构造器的关系,才能做更多的事情。就像是盖房子,地基打得越牢固,盖的房子越稳定。否则,盖得越高,危险性越大。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/77561.html
摘要:构造块优先于构造函数执行,如果存在多个构造代码块,则执行顺序按照定义的顺序依次执行。静态代码块在中使用关键字声明的代码块。同步代码块需要写在方法中。 代码块 在java中用{}括起来的称为代码块,代码块可分为以下四种: 普通代码块 构造代码块 静态代码块 同步代码块 普通代码块 在方法或语句中出现的{}就称为普通代码块。普通代码块和一般语句的执行顺序由他们在代码中出现的次序决定,先...
摘要:没有关键字修饰的如实例变量非静态变量非静态代码块初始化实际上是会被提取到类的构造器中被执行的,但是会比类构造器中的代码块优先执行到,非静态实例变量非静态代码块的地位是相等的,它们将按顺序被执行。 阅读原文:Java代码执行顺序 程序中代码执行的顺序非常重要,稍有不慎便会是程序运行出错,那么我将结合实例来分析代码中的执行。 名词解释 首先了解几个名词: 非静态代码块 直接由 { } 包起...
摘要:代码块我们主要观察普通代码块构造块静态块的主要作用。代码实例构造方法类的构造方法将代码块写在了类里面类的构造块控制台输出类的构造块类的构造方法此时实例化类对象时,虽然执行的是类的构造方法,但是构造块里面的代码也执行了。 代码块 我们主要观察普通代码块、构造块、静态块的主要作用。 在程序编写之中可以直接使用{} 定义一段语句,那么根据此部分定义的位置以及关键字的不同可以分为以下几种: ...
摘要:父类,子类子类方法三者中有同名变量时,调用子类方法输出,输出,为子类方法中的值,表示子类中的值,表示父类中的值。静态代码块构造代码块构造方法静态代码块构造代码块构造方法父类和子类都有静态代码块,构造代码块,构造方法,初始化子类对象。 package cat1; class fu{ public int num=10; public fu() { Sy...
这是网易2015校招Java面试题,直接上题目。 题目 package com.mousycoder.staticTest; public class HelloB extends HelloA { public HelloB() { System.out.println(HelloB); } { System.out.println(I...
阅读 3500·2021-08-02 13:41
阅读 2257·2019-08-30 15:56
阅读 1492·2019-08-30 11:17
阅读 1148·2019-08-29 15:18
阅读 546·2019-08-29 11:10
阅读 2637·2019-08-26 13:52
阅读 480·2019-08-26 13:22
阅读 2902·2019-08-23 15:41