由于Java 中的一切东西都是对象,所以许多活动 变得更加简单,这个问题便是其中的一例。

  除非真的需要代码,否则那个文件是不会载入的。通常,我们可认为除非那个类的一个对象构造完毕,  否则代码不会真的载入。由于static 方法存在一些细微的歧义,所以也能认为“类代码在首次使用的时候载入”。 首次使用的地方也是static 初始化发生的地方。装载的时候,所有static 对象和static 代码块都会按照本 来的顺序初始化(亦即它们在类定义代码里写入的顺序)。当然,static 数据只会初始化一次。

  简要的说就是,在类有继承关系时,类加载器上溯造型,进行相关类的加载工作。

比如:

Class B extends Class A
当我们new B()时,类加载器自动加载A的代码

class的初始化顺序

通常是以下这样的初始化顺序:

(static对象和static代码块,依据他们的顺序进行初始化)->成员变量和代码块(依据他们的顺序进行初始化)->构造函数

例如:

package cn.d;

public class ClassInit {

    public static void main(String[] args) {

        new B();
System.out.println("------------");
new B();
} } class A {
static {
System.out.println("A的static代码块...");//
}
{
System.out.println("A的代码块...");//
}
public String s1 = prtString("A的成员变量...");
public static String s2 = prtString("A的static变量...");// public A() {
System.out.println("A的构造函数...");
} public static String prtString(String str) {
System.out.println(str);
return null;
}
} class B extends A {
public String ss1 = prtString("B的成员变量...");
{
System.out.println("B的代码块...");
}
public static String ss2 = prtString("B的static变量...");// 3. public B() {
System.out.println("B的构造函数...");
} private static A a = new A();// 4.
static {
System.out.println("B的static代码块...");
}
}

结果:

A的static代码块...
A的static变量...
B的static变量...
A的代码块...
A的成员变量...
A的构造函数...
B的static代码块...
A的代码块...
A的成员变量...
A的构造函数...
B的成员变量...
B的代码块...
B的构造函数...

------------
A的代码块...
A的成员变量...
A的构造函数...
B的成员变量...
B的代码块...
B的构造函数...

解释:

1.  首先加载A的静态代码快和静态变量,由于A中静态代码块刈写在前面,因此先加载静态代码块后加载静态变量。
2.  然后加载B的静态代码快和静态成员变量,由于B中静态变量在前面所以先加载B的静态变量,当执行到 private static A a = new A();的时候会先加载A的成员变量再执行A的构造函数。最后执行B的静态代码块
3.  接下来加载成员变量、代码块和构造函数,先加载父类的成员变量、代码块和构造函数,然后加载子类的成员变量,子类的代码块,子类的构造函数。(成员变量和代码块优先级高于构造函数,成员变量和代码块是按照顺序加载)
4. 静态的东西只会在类加载器加载类的时候初始化,当JVM的方法区已经加载该类的时候不会再次加载静态信息
5.  调用子类的构造方法会调用父类的构造方法。

总结:

  1.先静后动,先父后子

  2.静态代码块和静态成员变量>代码块和成员变量>构造函数

  3.静态代码块和静态成员变量、代码块和成员变量是按照代码中定义顺序进行加载。

我们可以查看上面代码编译后的结果

A.class

import java.io.PrintStream;

class A
{
public String s1; static
{
System.out.println("A的static代码块...");
} public static String s2 = prtString("A的static变量..."); public A()
{
System.out.println("A的代码块..."); this.s1 = prtString("A的成员变量..."); System.out.println("A的构造函数...");
} public static String prtString(String paramString)
{
System.out.println(paramString);
return null;
}
}

B.class

import java.io.PrintStream;

class B
extends A
{
public String ss1 = prtString("B的成员变量...");
public static String ss2 = prtString("B的static变量..."); public B()
{
System.out.println("B的代码块..."); System.out.println("B的构造函数...");
} private static A a = new A(); static
{
System.out.println("B的static代码块...");
}
}

补充:Java编译器会在编译的时候做一些优化,有时候我们可能考虑顺序问题,比如:

public class TestClass {
static{
s = "ssssssssssssssss";
}
private static String s; public static void main(String[] args) {
System.out.println(s);
}
}

编译后代码:

import java.io.PrintStream;

public class TestClass
{
private static String s = "ssssssssssssssss"; public static void main(String[] paramArrayOfString)
{
System.out.println(s);
}
}

补充:关于子类对象中调用父类构造方法的原因-------------这不是创建两个对象,仅创建了一个子对象。父类的构造函数被调用是考虑到其可能有私有的属性需要通过自身的构造函数初始化

   在子类的构造函数(constructor)中super()必须被首先调用,如果super()没有被调用,则编译器将在构造函数(constructor)的第一行插入对super()的调用。这就是为什么当创建一个子类的对象时会调用父类的构造函数(constructor)的原因。

  如果父类定义了自己的有参构造方法,而且没有定义无参构造方法,则子类必须在构造方法第一行显示调用父类的有参构造方法。否则编译不通过。

  如果父类既有无参构造也有有参构造,子类可以不显示调用,编译后会自动调用无参构造方法。

  

  Java对上面的限制也满足子类的对象是父类的对象。

  简单的说:   子类的构造函数必须引用父类的构造函数,由程序猿显示调用或由编译器隐式调用,对于这两种方式,被引用的父类构造函数必须已被定义。

继承的基本概念:
(1)Java不支持多继承,也就是说子类至多只能有一个父类。
(2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。
(3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。
(4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。

  可以简单的理解为创建子类的时候调用父类的构造方法是父类成员变量在子类空间中初始化。(我们可以称此为父类子对象)

  相同的方法会被重写,变量没有重写之说,如果子类声明了跟父类一样的变量,那意味着子类将有两个相同名称的变量。一个存放在子类实例对象中,一个存放在父类子对象中。父类的private变量,也会被继承并且初始化在子类父对象中,只不过对外不可见。

  super关键字在java中的作用是使被屏蔽的成员变量或者成员方法变为可见,或者说用来引用被屏蔽的成员变量或成员方法,super只是记录在对象内部的父类特征(属性和方法)的一个引用。啥叫被屏蔽的成员变量或成员方法?就是被子类重写了的方法和定义了跟父类相同的成员变量,由于不能被继承,所以就称作被屏蔽。(所以super关键字只能在子类中使用)

  关于继承的内存分配可以参考:https://blog.csdn.net/xiaochuhe_lx/article/details/9126445

Java中class的初始化顺序的更多相关文章

  1. Java中的成员初始化顺序和内存分配过程

    Java中的成员初始化顺序和内存分配过程 原帖是这样描述的: http://java.dzone.com/articles/java-object-initialization?utm_source= ...

  2. Java 类成员的初始化顺序

    Java 类成员的初始化顺序 前言:开发中碰到一个Java文件中有很多的成员变量,包括静态和非静态的,还有很多的初始化方法,很好奇这些成员的初始化顺序,在这里作个研究.   1  无继承情况下的Jav ...

  3. java类的成员初始化顺序和初始化块知识

    java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...

  4. Java中数组的初始化方式

    Java中数组的初始化方式    初始化方式有两种: 1.静态初始化:初始化时由程序猿显式指定每一个数组元素的初始值,由系统指定数组长度 2.动态初始化:初始化时由程序猿仅仅指定数组长度,由系统为数组 ...

  5. java中的TreeMap如何顺序按照插入顺序排序

    java中的TreeMap如何顺序按照插入顺序排序 你可以使用LinkedHashMap  这个是可以记住插入顺序的. 用LinkedHashMap吧.它内部有一个链表,保持插入的顺序.迭代的时候,也 ...

  6. java中的静态初始化块

    Java 中可以通过初始化块进行数据赋值.如: 在类的声明中,可以包含多个初始化块,当创建类的实例时,就会依次执行这些代码块.如果使用 static 修饰初始化块,就称为静态初始化块. 需要特别注意: ...

  7. Java类的成员初始化顺序

    Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...

  8. [转载]Java中异常的捕获顺序(多个catch)

    http://blog.sina.com.cn/s/blog_6b022bc60101cdbv.html [转载]Java中异常的捕获顺序(多个catch) (2012-11-05 09:47:28) ...

  9. java类中成员的初始化顺序(一)

    类被创建之后的成员的初始化顺序到底是怎么样的? 首先 不考虑继承 package com; public class DemoOne { /** * 关于类的初始化顺序 */ //不考虑继承结构的情况 ...

随机推荐

  1. 【Redis】- 主从复制

    Redis跟MySQL一样,拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构. redis的主从 ...

  2. Python2中编码错误---重组人表皮生长因子凝胶(易孚格式转化为UTF-8

    在python2的使用中,总会遇到各种各样的编码问题,这也是使用Python2最头疼的一件事情,幸好python3解决了编码的问题. 下面我在爬虫时遇到的类似重组人表皮生长 ...

  3. Android------去除标题栏

    这里暂时只给出一种方法,在java代码中去除 1.继承Activity 在onCreate方法中 getWindow().setFlags(WindowManager.LayoutParams.FLA ...

  4. linux路由表的配置

    linux路由表的配置 一.原理说明 1.路由表(table)从0到255进行编号,每个编号可以对应一个别名,编号和别名的对应关系在linux下放在/etc/iproute2/rt_tables这个文 ...

  5. Redis Cluster实现原理

    一.Redis Cluster主要特性和设计     集群目标 1)高性能和线性扩展,最大可以支撑到1000个节点:Cluster架构中无Proxy层,Master与slave之间使用异步replic ...

  6. Go语言【第三篇】:Go变量和常量

    Go语言变量 变量来源于数学,是计算机语言中能存储计算结果或能表示值抽象概念.变量可以通过变量名访问.Go语言变量名由字母.数字.下划线组成,其中首字母不能为数字,声明变量的一般形式是使用var关键字 ...

  7. Django 2.0 学习(06):Django 视图(进阶)

    概述 Django中的特方法,该方法代表了Django的Web页面,并且视图具有特定的模板.以博客应用为例进行说明,在博客应用中应该包含下面的视图: 博客主页:显示最近的一些记录: 详细页面:单个详细 ...

  8. 洛谷 P4555 [国家集训队]最长双回文串 解题报告

    P4555 [国家集训队]最长双回文串 题目描述 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为abc,逆序为cba,不相同). 输入长度为\(n\)的串 ...

  9. UVA.548 Tree(二叉树 DFS)

    UVA.548 Tree(二叉树 DFS) 题意分析 给出一棵树的中序遍历和后序遍历,从所有叶子节点中找到一个使得其到根节点的权值最小.若有多个,输出叶子节点本身权值小的那个节点. 先递归建树,然后D ...

  10. 直通BAT面试算法精讲课1

    1.有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树. 给定二叉树的根结点root,请返回打印结果,结果按照每一层一个数组进行储存,所有数组的顺序按照层数从上往下,且每一层的数组内元素按照从左往右 ...