Java中class的初始化顺序
由于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的初始化顺序的更多相关文章
- Java中的成员初始化顺序和内存分配过程
Java中的成员初始化顺序和内存分配过程 原帖是这样描述的: http://java.dzone.com/articles/java-object-initialization?utm_source= ...
- Java 类成员的初始化顺序
Java 类成员的初始化顺序 前言:开发中碰到一个Java文件中有很多的成员变量,包括静态和非静态的,还有很多的初始化方法,很好奇这些成员的初始化顺序,在这里作个研究. 1 无继承情况下的Jav ...
- java类的成员初始化顺序和初始化块知识
java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...
- Java中数组的初始化方式
Java中数组的初始化方式 初始化方式有两种: 1.静态初始化:初始化时由程序猿显式指定每一个数组元素的初始值,由系统指定数组长度 2.动态初始化:初始化时由程序猿仅仅指定数组长度,由系统为数组 ...
- java中的TreeMap如何顺序按照插入顺序排序
java中的TreeMap如何顺序按照插入顺序排序 你可以使用LinkedHashMap 这个是可以记住插入顺序的. 用LinkedHashMap吧.它内部有一个链表,保持插入的顺序.迭代的时候,也 ...
- java中的静态初始化块
Java 中可以通过初始化块进行数据赋值.如: 在类的声明中,可以包含多个初始化块,当创建类的实例时,就会依次执行这些代码块.如果使用 static 修饰初始化块,就称为静态初始化块. 需要特别注意: ...
- Java类的成员初始化顺序
Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...
- [转载]Java中异常的捕获顺序(多个catch)
http://blog.sina.com.cn/s/blog_6b022bc60101cdbv.html [转载]Java中异常的捕获顺序(多个catch) (2012-11-05 09:47:28) ...
- java类中成员的初始化顺序(一)
类被创建之后的成员的初始化顺序到底是怎么样的? 首先 不考虑继承 package com; public class DemoOne { /** * 关于类的初始化顺序 */ //不考虑继承结构的情况 ...
随机推荐
- 【Linux】- ps 命令
Linux ps命令用于显示当前进程 (process) 的状态. 语法 ps [options] [--help] 参数: -A 列出所有的行程 -w 显示加宽可以显示较多的资讯 -a ...
- Agile.Net 组件式开发平台 - 服务开发示例
在上一篇文章中已经讲解了组件的开发,这篇文章讲解平台服务开发. Agile.Net开发管理平台项目,已经托管在开源中国码云平台(http://git.oschina.net) 登陆码云平台进入项目主页 ...
- BER-TLV数据结构
本文是自身在研究学习过程中碰到的问题,整理而成. 为了便于后文的引用说明,先列出一段TLV结构的数据: [6F] 4D │ ├─[] A0000003330101 │ ├─[A5] │ │ ├─[] ...
- dpr dproj 扩展名区别,dprdproj
这段时间用xe6,看了下目录下生成的一些文件,因为隐藏了扩展名,看到两个名字一样的文件,右键属性看了下,同名但扩展名不同,百度了下区别,没有找到答案,问群里的朋友才知道区别,特此记录下来: dpr:D ...
- zoj3209-Treasure Map
给出一个左下角为\((0,0)\),右上角为\((n,m)\)的矩形,再给出\(k\)个在大矩形内的小矩形(可以重合),问是否能用这些小矩形完全覆盖这个大矩形,并且没有重合,如果可以至少需要多少个. ...
- BZOJ 1816 扑克牌(二分)
由于答案具有单调性,考虑二分答案并验证. 如果能凑齐x堆,因为每个joke在一个牌堆里最多只能用一次,则至多只能用min(x,m)个joke. 对于每个牌,如果这个牌的总数小于x,用joke补齐剩下的 ...
- 配置bond和vlan
网卡是光口还是电口的方法ethtool 网卡名字 一看速度二看port是否是firber首先查看需要做bond的物理网卡,如enp130s0f0,enp131s0f0以物理网卡为enp130s0f0, ...
- 转:Simple Introduction to Dirichlet Process
来源:http://hi.baidu.com/vyfrcemnsnbgxyd/item/2f10ecc3fc35597dced4f88b Dirichlet Process(DP)是一个很重要的统计模 ...
- 【刷题】UOJ #34 多项式乘法
这是一道模板题. 给你两个多项式,请输出乘起来后的多项式. 输入格式 第一行两个整数 \(n\) 和 \(m\) ,分别表示两个多项式的次数. 第二行 \(n+1\) 个整数,表示第一个多项式的 \( ...
- bzoj 1103: [POI2007]大都市meg (dfs序)
dfs序,加个bit维护前缀和就行了 type arr=record toward,next:longint; end; const maxn=; var edge:..maxn]of arr; bi ...