九、 Java程序初始化的顺序(二)
之前的一篇博客里我写了关于在一个类中的程序初始化顺序,但是在Java的面向对象里,类之间还存在着继承的关系。所以关于程序的初始化顺序,我们可以再细划分为:父类静态变量,父类的静态代码块,父类构造器,父类非静态变量,父类非静态代码块,子类静态变量,子类静态代码块,子类构造器,子类非静态成员变量和子类非静态代码块。
本篇博客我们讨论的就是关于程序初始化的过程中,上述的成员在初始化加载先后顺序。 在此前我们讨论得出的结论:在一个类中,Java程序加载的顺序是:静态变量-->静态代码块-->非静态变量-->非静态代码块-->构造器. 父类的代码:
public class SuperClass {
//父类与子类都在一个包中,这里我们就使用default修饰符
//这是一个父类的静态变量,此时还是初始化的默认值null
static String superStaticVariale;
// 静态代码块,给String赋值
static {
superStaticVariale = "父类静态代码块赋值成功";
System.out.println("此时运行的是父类的静态代码块:"+superStaticVariale);
}
// 无参构造,覆盖静态代码块的值
SuperClass(){
superStaticVariale = "父类构造器赋值成功";
System.out.println("此时运行的是父类的构造器:"+superStaticVariale);
}
//定义一个非静态变量
String superVariale;
// 定义一个非静态代码块
{
superVariale = "父类非静态代码块赋值";
System.out.println("此时运行的是父类的非静态代码块:"+superVariale);
}
}
子类的代码:
public class SubClass extends SuperClass{
static String subStaticVariale;
// 静态代码块,给String赋值
static {
subStaticVariale = "子类静态代码块赋值成功";
System.out.println("此时运行的是子类的静态代码块:"+subStaticVariale);
}
// 无参构造,覆盖静态代码块的值
SubClass(){
superStaticVariale = "子类构造器赋值成功";
System.out.println("此时运行的是子类的构造器:"+superStaticVariale);
}
//定义一个非静态变量
String subVariale;
// 定义一个非静态代码块
{
subVariale = "子类非静态代码块赋值";
System.out.println("此时运行的是子类非静态代码块:"+subVariale);
}
}
测试代码:
public class Main {
public static void main(String[] args) {
SubClass s = new SubClass();
}
}
运行结果:
```
此时运行的是父类的静态代码块:父类静态代码块赋值成功
此时运行的是子类的静态代码块:子类静态代码块赋值成功
此时运行的是父类的非静态代码块:父类非静态代码块赋值
此时运行的是父类的构造器:父类构造器赋值成功
此时运行的是子类非静态代码块:子类非静态代码块赋值
此时运行的是子类的构造器:子类构造器赋值成功
```
很显然,在继承关系中,代码的加载顺序是:父类的静态变量-->父类的静态代码块-->子类静态变量-->子类的静态代码块-->父类非静态变量-->父类的非静态代码块-->父类的构造器-->子类非静态变量-->子类非静态代码块-->子类构造器 进一步测试:
public class Main {
public static void main(String[] args) {
SubClass s = new SubClass();
SubClass s1 = new SubClass();
SubClass s2 = new SubClass();
}
}
运行结果:
```
此时运行的是父类的静态代码块:父类静态代码块赋值成功
此时运行的是子类的静态代码块:子类静态代码块赋值成功
此时运行的是父类的非静态代码块:父类非静态代码块赋值
此时运行的是父类的构造器:父类构造器赋值成功
此时运行的是子类非静态代码块:子类非静态代码块赋值
此时运行的是子类的构造器:子类构造器赋值成功
此时运行的是父类的非静态代码块:父类非静态代码块赋值
此时运行的是父类的构造器:父类构造器赋值成功
此时运行的是子类非静态代码块:子类非静态代码块赋值
此时运行的是子类的构造器:子类构造器赋值成功
此时运行的是父类的非静态代码块:父类非静态代码块赋值
此时运行的是父类的构造器:父类构造器赋值成功
此时运行的是子类非静态代码块:子类非静态代码块赋值
此时运行的是子类的构造器:子类构造器赋值成功
```
得出结论:
父类与子类的静态代码都只执行一次,然后非静态代码块与构造器是组合出现的。 简化一下代码:
public class Main {
public static void main(String[] args) {
C c= new C();
}
}
class A{
A(){
System.out.println("A的无参构造器");
}
}
class B extends A{
// B(int a){
B(){
System.out.println("B的无参构造器");
}
}
class C extends B{
C(){
System.out.println("C的无参构造器");
}
}
运行结果:
```text
A的无参构造器
B的无参构造器
C的无参构造器
```
调用C的构造器生成C的实例对象会从最上级的父类的无参构造器开始逐层调用,那么我们的类都继承了一个超级父类Object,也就是在我们最初的错误代码中,我们调用Student的无参构造创建一个对象时,首先会调用这个对象的父类Object的无参构造器,
class Student{
String name;
{
name = "老大";
}
Student(){
this(name);//这样会报错
super();
System.out.println("题目要求写一个无参的构造器");
}
Student(String name){
this.name = name;
System.out.println(name);
}
}
子类实例化默认调用父类的无参构造器,也就是如上this调用在super()之前(实际中这两者不会同时出现),name此时是非静态属性,此时会报错错误: 无法在调用超类型构造器之前引用name。
class Student{
static String name;
{
name = "老大";
}
Student(){
this(name);
System.out.println("题目要求写一个无参的构造器");
}
Student(String name){
this.name = name;
System.out.println(name);
}
}
当name是静态属性时,代码块是非静态时,编译通过,调用子类的无参构造器时this(name),输出结果是:
```text
null
题目要求写一个无参的构造器
```
此时的this()调用实参构造并没有赋值成功。
class Student{
static String name;
static{
name = "老大";
}
Student(){
this(name);
System.out.println("题目要求写一个无参的构造器");
}
Student(String name){
this.name = name;
System.out.println(name);
}
}
此时运行结果:
```text
老大
题目要求写一个无参的构造器
```
这样赋值成功。由此证明我们的结论是正确的,this()是在子类父类构造器之前进行的操作super(),当子类代码块是非静态时,子类非静态代码块会在执行父类构造器之后执行,所以this(name)时name还没有被赋值,所以打印是null。 结论:
1. 一个类中可以在无参构造器中调用此类的有参构造器(顺序反过来);
2. 在执行子类的无参构造器时会默认调用最高级父类无参构造,并逐级调用直至子类的无参构造;
3. Java程序的加载顺为父类的静态变量-->父类的静态代码块-->子类静态变量-->子类的静态代码块-->父类非静态变量-->父类的非静态代码块-->父类的构造器-->子类非静态变量-->子类非静态代码块-->子类构造器,且静态变量或代码块无论构造器调用多少次,他只会执行一次,后面再调用构造器则会执行非静态属性及代码块构造器。 最后关于为什么子类会调用父类的构造器,这个从设计着的角度来看是为了给从父类继承的属性初始化,子类需要知道父类是如何给属性初始化的。
九、 Java程序初始化的顺序(二)的更多相关文章
- Java程序初始化的顺序
Java程序初始化的顺序 java程序初始化工作可以在许多不同的代码块中来完成(例如:静态代码块.构造函数等),他们执行的顺序如下: 父类静态变量 父类静态代码块 子类静态变量 子类静态代码块 父类非 ...
- 《Java程序员面试笔试宝典》之Java程序初始化的顺序是怎样的
在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下三原则优 ...
- 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的
在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下 ...
- 八、 Java程序初始化的顺序(一)
今天在写构造器方法的时候,遇到了一个小问题,由这个问题引发了一连串的思考,在一个Java类中变量与类的初始化执行顺序是什么样的呢?## 发现问题 class Student{ private Stri ...
- java程序初始化顺序
使用场景: 在java程序中,当实例化对象时,对象的所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后, 才会调用对象所在类的构造函数创建对象. 初始化的原则: (1)静态对象优先于 ...
- Java中程序初始化的顺序
1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码: class Test01...{ public ...
- Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)
1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...
- 实现Java程序跨平台运行十二个注意事项
[转自] http://blog.chinaunix.net/uid-20550186-id-1927257.html 使用Java语言编写应用程序最大的优点在于"一次编译,处处运行&quo ...
- JAVA学习第十九课(java程序的异常处理 (二))
异常处理的捕捉形式: 这是能够对异常进行针对性处理的方式 六.try.catch的理解 详细格式: try { //须要被检測异常的代码 } catch(异常类 变量)//改变量用于接受发生异常的对象 ...
随机推荐
- 10.VUE学习之使用lodash库减少watch对后台请求的压力
问题描述 使用watch监听库里word的值的变化,获取新值后,用oxios发送的ajax异步请求, 此时会多次发送请求,浪费服务器资料. 解决办法 使用lodash库里的_.debounce函数延缓 ...
- 第37课 thinkphp5添加商品基本信息及通过前置钩子上传商品主图 模型事件(勾子函数)
目录 手册地址: before_insert(新增之前的操作) 要实现的功能 思路 触发条件: 1. 控制器里必须要调用模型的save()方式保存数据,用insert()触发不了勾子函数的 2. 模型 ...
- GoF23种设计模式之创建型模式之原型模式
一.概述 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 二.适用性 1.当一个系统应该独立于它的产品创建.构成和表示的时候. 2.当要实例化的类是在运行时刻指定的时候,例如:通过动 ...
- 初学js之qq聊天实例
实现的功能为上图所示,但是每新发送的消息必须显示在最上面. 我实现了两版,样式有是一样的.我们直接看代码. 版本一: <!DOCTYPE html> <html lang=" ...
- A1083 List Grades (25)(25 分)
A1083 List Grades (25)(25 分) Given a list of N student records with name, ID and grade. You are supp ...
- 笔记-urllib-parse
笔记-urllib-parse 1. 简介模块官方解释This module defines a standard interface to break Uniform Resource Locato ...
- android 极光推送 声音与振动 的关闭和开启
前言:最近刚好在写一些推送方面的东西,又是新手,不断在网上找资料,很少,不过还是找到了一些,反正百度我是再也不想百度了,谷歌一下子就能找到想要的. 废话不多说. 1.主要方法就是如下一个函数 priv ...
- ECharts的x轴和y轴均使用数值类型
今天有个需求,就是需要ECharts的x轴和y轴都要使用数值类型,即xAxis.type和yAxis.type均为value,然后我按照我以为的方式修改了下,发现图崩了 发现问题: 然后我打开了ECh ...
- python-侦测系统
大概就是这样 要求 告警需要一定之间内出现多次 然后才报警一次 如果恢复 必须发送恢复的信息
- vue知识
https://juejin.im/post/5af16a2cf265da0b8636353b