之前的一篇博客里我写了关于在一个类中的程序初始化顺序,但是在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程序初始化的顺序(二)的更多相关文章

  1. Java程序初始化的顺序

    Java程序初始化的顺序 java程序初始化工作可以在许多不同的代码块中来完成(例如:静态代码块.构造函数等),他们执行的顺序如下: 父类静态变量 父类静态代码块 子类静态变量 子类静态代码块 父类非 ...

  2. 《Java程序员面试笔试宝典》之Java程序初始化的顺序是怎样的

    在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下三原则优 ...

  3. 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的

    在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象.    Java程序的初始化一般遵循以下三个原则(以下 ...

  4. 八、 Java程序初始化的顺序(一)

    今天在写构造器方法的时候,遇到了一个小问题,由这个问题引发了一连串的思考,在一个Java类中变量与类的初始化执行顺序是什么样的呢?## 发现问题 class Student{ private Stri ...

  5. java程序初始化顺序

    使用场景:  在java程序中,当实例化对象时,对象的所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后, 才会调用对象所在类的构造函数创建对象. 初始化的原则: (1)静态对象优先于 ...

  6. Java中程序初始化的顺序

    1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码: class Test01...{ public ...

  7. Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)

    1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...

  8. 实现Java程序跨平台运行十二个注意事项

    [转自] http://blog.chinaunix.net/uid-20550186-id-1927257.html 使用Java语言编写应用程序最大的优点在于"一次编译,处处运行&quo ...

  9. JAVA学习第十九课(java程序的异常处理 (二))

    异常处理的捕捉形式: 这是能够对异常进行针对性处理的方式 六.try.catch的理解 详细格式: try { //须要被检測异常的代码 } catch(异常类 变量)//改变量用于接受发生异常的对象 ...

随机推荐

  1. JZOJ 5809. 【NOIP2008模拟】数羊

    5809. [NOIP2008模拟]数羊 (File IO): input:sheep.in output:sheep.out Time Limits: 1000 ms  Memory Limits: ...

  2. 13.VUE学习之控制行内样式

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  3. Zookeeper协调服务系统·ELK日志管理系统简介

    Zookeeper协调服务系统: 说明:它分布式系统中的协调服务系统,是Hadoop下的一个子项目,可提供的服务有:名字服务.配置服务.分布式同步.组服务等. 3个角色:Leaders.Follow. ...

  4. 在virtualBox中打开vdi(转载)

    在VirtualBox中启动“新建虚拟机”向导.第一步,输入名称“ubuntu”,选择系统类型为“Linux 2.6”.第二步,内存大小默认是256MB,不变.第三步,虚拟硬盘,点击按钮“现有”,在新 ...

  5. Linux命令之---diff

    命令介绍 diff命令可以酌行比较纯文本文件内的内容,并输出文件的差异. 命令格式 diff [option] [file1] [file2] 举例子 1)比较俩文本文件 [root@king ~]# ...

  6. Unity脚本执行顺序自研框架

    本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/52372611 作者:car ...

  7. java高级编程技巧

    1. boolean a= b==null;这句话很亮. public class Test { public static void main(String[] args) { String b=& ...

  8. RF,GBDT,XGBoost,lightGBM的对比

    转载地址:https://blog.csdn.net/u014248127/article/details/79015803 RF,GBDT,XGBoost,lightGBM都属于集成学习(Ensem ...

  9. ogre3D学习基础5 -- 阴影与动画

    五.阴影 阴影是渲染一个真实场景的重要组成部分,它可以给场景中的物体提供更加真实的感觉,同时还可以帮助用户更好的了解对象间的空间关系. 启用阴影: 缺省情况下,阴影是关闭的,开启方式如下: 1.建立场 ...

  10. 《HTTP协议详解》读书笔记---请求篇之情求方法

    之前对于网络这一块不是很清楚,值知道TCP/IP协议,三次握手四次握手之类的很笼统,零碎的知识,现在打算系统学习下网络相关的知识,先从http协议开始. 本人,还是新手,对于一些知识如果有理解错误的, ...