Java中程序初始化的顺序
1,在一个类的内部(不考虑它是另一个类的派生类):很多人认为,类的成员变量是在构造方法调用之后再初始化的,先不考虑这种观点的正确性,先看一下下面的代码:
- class Test01...{
- public Test01(int i)...{
- System.out.println("Test01 of constractor : " + i);
- }
- }
- public class Test02 ...{
- private Test01 t1 = new Test01(1);
- private int n = 10;
- public Test02()...{
- System.out.println("Test02 of constructor : " + n);
- }
- private Test01 t2 = new Test01(2);
- public static void main(String[] args) ...{
- Test02 test = new Test02();
- }
- }
- 输出的结果为:
- Test01 of constractor : 1
- Test01 of constractor : 2
- Test02 of constructor : 10
通过输出,可见当生成Test02的实例test时,它并不是首先调用其构造方法而是先是成员变量的初始化,而且成员的初始化的顺序以成员变量的定义顺序有关,先定义的先初始化,初始化后再调用构造方法。其实成员变量的初始化,在类的所有方法调用之前进行,包括构造方法
当类中有Static 修饰的成员呢?测试下面一段代码:
- public class Test03 ...{
- private int i1 = printCommon();
- private static int i2 = printStatic();
- public Test03()...{
- }
- public static int printCommon()...{
- System.out.println("i1 is init!");
- return 1;
- }
- public static int printStatic()...{
- System.out.println("i2 is init!");
- return 2;
- }
- public static void main(String[] args) ...{
- Test03 t = new Test03();
- }
- }
- 输出结果为:
- i2 is init!
- i1 is init!
可见static的成员比普通的成员变量先初始化。
我们都知道,如果一个类的成员变量没有在定义时,系统会给予系统默认的值,有=号的就直接给予右值,系统在给予初值和=号给予值这2中方式,在执行时间上有先后吗?为了测试,我编写了如下代码:
- public class Test04 ...{
- private static Test04 t1 = new Test04();
- private static int i1;
- private static int i2 = 2;
- public Test04()...{
- i1++;
- i2++;
- }
- public static void main(String[] args) ...{
- Test04 t2 = new Test04();
- System.out.println("t2.i1 = " + t2.i1);
- System.out.println("t2.i2 = " + t2.i2);
- }
- }
- 我们先预计一下输出,可能有几种答案:2和3,3和3,2和2
- 执行代码后:
- t2.i1 = 2
- t2.i2 = 3
为什么是2和3呢?其实代码的执行顺序是这样的:首先执行给t1,i1,i2分别给予初始值null,0,0,再执行
Test04 t1 =new Test04(),这样i1++,i2++被执行,i1,i2都变为1,执行完毕后接着执行int i1; i1,i2的值仍然是1,1,当执行int i2 = 2时i2被赋予了值,即i1 = 1,i2=2;再执行Test04 t2 = new Test04(),i1,i2再执行++,此时i1 =2,i2 =3,输出i1,i2,结果就是:t2.i1 = 2,t2.i2 = 3。 通过上面的代码我们可以认为系统默认值的给予比通过等号的赋予先执行。
2,一个类还有上层的类,即父类:
当生成一个子类时,大家到知道会调用父类的构造方法。如果子类和父类中都有Static的成员变量呢,其实我们在深入分析一个类的内部初始化后,对于存在父类的类的初始化其实原理都一样,具体以下面的代码为例:
- class SuperClass ...{
- static...{
- System.out.println("SuperClass of static block");
- }
- public SuperClass()...{
- System.out.println("SuperClass of constracutor");
- }
- }
- public class SubClass extends SuperClass...{
- static...{
- System.out.println("SubClass of static block");
- }
- public SubClass()...{
- System.out.println("SubClass of constracutor");
- }
- public static void main(String[] args)...{
- SuperClass t = new SubClass();
- }
- }
- 输出结果:
- SuperClass of static block
- SubClass of static block
- SuperClass of constracutor
- SubClass of constracutor
可见当父类,和子类有Static时,先初始化Static,再初始化子类的Static,再初始化父类的其他成员变量->父类构造方法->子类其他成员变量->子类的构造方法。
父类上层还有父类时,总是先执行最顶层父类的Static-->派生类Static-->派生类Static-->.......-->子类Static-->顶层父类的其他成员变量-->父类构造方法--> 派生类的其他成员变量 --> 派生类构造方法--> ...............-->子类其他成员变量-->子类构造方法
讨论到继承,就不得提一下多态:
如果父类构造方法的代码中有子类中被重写得方法,当执行这样的语句
SuperClass super = new SubClass();
初始化时调用父类的构造方法,是执行父类的原方法,还是执行子类中被重写的方法呢?
- class SuperClass...{
- public SuperClass()...{
- System.out.println("SuperClass of constructor");
- m();
- }
- public void m()...{
- System.out.println("SuperClass.m()");
- }
- }
- public class SubClassTest extends SuperClass ...{
- private int i = 10;
- public SubClassTest()...{
- System.out.println("SubClass of constructor");
- super.m();
- m();
- }
- public void m()...{
- System.out.println("SubClass.m(): i = " + i);
- }
- public static void main(String[] args)...{
- SuperClass t = new SubClassTest();
- }
- }
- 可能很多人会认为输出为:
- SuperClass of constructor
- SubClass.m(): i = 10
- SubClass of constructor
- SuperClass.m()
- SubClass.m(): i = 10
- 其实不然!
- 正确输出为:
- SuperClass of constructor
- SubClass.m(): i = 0
- SubClass of constructor
- SuperClass.m()
- SubClass.m(): i = 10
- 在生成对象时,父类调用的M()方法,不是父类的 M()方法,而时子类中被重写了的M()方法!!并且还出现一个怪异的现象,子类的privte int i 也被父类访问到,这不是和我们说private的成员只能在本类使用的原则相违背了吗?其实我们说的这条原则是编译期间所遵守的,在JAVA程序的编译期间,它只检查语法的合法性,在JAVA的JVM中,即运行期间,不管你声明的什么,对于JVM来说都是透明的,而多态是在运行期间执行的,所以能拿到SubClass的private成员,一点都不奇怪,只是此时还没执行 i = 10,所以在父类的构造方法中调用m()时,系统只能将i赋予系统初值0。
- 下面是我设计的一道完整的初始化例子,可测试你对类的初始化问题是否完整掌握:
- 写出程序运行的结果:
- class A...{
- private int i = 9;
- protected static int j;
- static...{
- System.out.println("-- Load First SuperClass of static block start!-- ");
- System.out.println("j = " + j);
- System.out.println("-- Load First SuperClass of static block End -- ");
- }
- public A()...{
- System.out.println("------- Load SuperClass of structor start --------");
- System.out.println("Frist print j = " + j);
- j = 10;
- m();
- System.out.println("k = " + k);
- System.out.println("Second print j = " + j);
- System.out.println("----------- Load SuperClass End ----------- ");
- }
- private static int k = getInt();
- public static int getInt()...{
- System.out.println("Load SuperClass.getInt() ");
- return 11;
- }
- static...{
- System.out.println("--- Load Second SuperClass of static block!-------");
- System.out.println("j = " + j);
- System.out.println("k = " + k);
- System.out.println("-- Load Second SuperClass of static block End -- ");
- }
- public void m()...{
- System.out.println("SuperClass.m() , " + "j = " +j);
- }
- }
- class B extends A ...{
- private int a = 10;
- static...{
- System.out.println("---- Load SubClass of static block!------");
- System.out.println("-- Load SubClass of static block End -- ");
- }
- public B()...{
- System.out.println("Load SubClass of structor");
- m();
- System.out.println("--- Load SubClass End ---- ");
- }
- public void m()...{
- System.out.println("SubClass.m() ," + "a = " + a );
- }
- }
- public class Test1...{
- public static void main(String[] args)...{
- A a = new B();
- }
- }
- 正确的答案为:
- -- Load First SuperClass of static block start!--
- j = 0
- -- Load First SuperClass of static block End --
- Load SuperClass.getInt()
- --- Load Second SuperClass of static block!-------
- j = 0
- k = 11
- -- Load Second SuperClass of static block End --
- ---- Load SubClass of static block!------
- -- Load SubClass of static block End --
- ------- Load SuperClass of structor start --------
- Frist print j = 0
- SubClass.m() ,a = 0
- k = 11
- Second print j = 10
- ----------- Load SuperClass End -----------
- Load SubClass of structor
- SubClass.m() ,a = 10
- --- Load SubClass End ----
下面需要说明的一点也是至关重要的一点:那就是成员变量的初始化和非static初始化块之间的执行顺序是按照他们出现的先后顺序来执行的
- public class Test04
- {
- //下面的这两行代码放置的顺序,跟执行结果是有关系的
- private String t1 = test();
- {
- System.out.println("初始化快!");
- }
- //上面的这两行代码放置的顺序,跟执行结果是有关系的
- private String test(){
- System.out.println("实例变量的执行过程");
- return "test";
- }
- public Test04()
- {
- System.out.println("构造方法!");
- }
- public static void main(String[] args)
- {
- Test04 t2 = new Test04();
- }
- }
实例变量的执行过程
初始化快!
构造方法!
public class NonStaticBlock {
{
System.out.println("初始化快!");
}
//下面的这两行代码放置的顺序,跟执行结果是有关系的
private String t1 = test();
//上面的这两行代码放置的顺序,跟执行结果是有关系的 private String test(){
System.out.println("实例变量的执行过程");
return "test";
} public NonStaticBlock()
{
System.out.println("构造方法!");
} public static void main(String[] args)
{
NonStaticBlock t2 = new NonStaticBlock();
} }
初始化快!
实例变量的执行过程
构造方法!
public class NonStaticBlock { //下面的这两行代码放置的顺序,跟执行结果是有关系的
private String t1 = test();
//上面的这两行代码放置的顺序,跟执行结果是有关系的 private String test(){
System.out.println("实例变量的执行过程");
return "test";
} public NonStaticBlock()
{
System.out.println("构造方法!");
}
{
System.out.println("初始化快!");
}
public static void main(String[] args)
{
NonStaticBlock t2 = new NonStaticBlock();
} }
实例变量的执行过程
初始化快!
构造方法!
Java中程序初始化的顺序的更多相关文章
- Java程序初始化的顺序
Java程序初始化的顺序 java程序初始化工作可以在许多不同的代码块中来完成(例如:静态代码块.构造函数等),他们执行的顺序如下: 父类静态变量 父类静态代码块 子类静态变量 子类静态代码块 父类非 ...
- 初步探究java中程序退出、GC垃圾回收时,socket tcp连接的行为
初步探究java中程序退出.GC垃圾回收时,socket tcp连接的行为 今天在项目开发中需要用到socket tcp连接相关(作为tcp客户端),在思考中发觉需要理清socket主动.被动关闭时发 ...
- Java中的初始化详细解析
今天所要详细讲解的是Java中的初始化,也就是new对象的过程中,其程序的行走流程. 先说没有静态成员变量和静态代码块的情况. public class NormalInit { public sta ...
- [转载]Java中异常的捕获顺序(多个catch)
http://blog.sina.com.cn/s/blog_6b022bc60101cdbv.html [转载]Java中异常的捕获顺序(多个catch) (2012-11-05 09:47:28) ...
- java中的TreeMap如何顺序按照插入顺序排序
java中的TreeMap如何顺序按照插入顺序排序 你可以使用LinkedHashMap 这个是可以记住插入顺序的. 用LinkedHashMap吧.它内部有一个链表,保持插入的顺序.迭代的时候,也 ...
- 浅谈Java中静态初始化块跟非初始化块
众所周知在JAVA编程语言中有两种初始化块: 静态初始化块 非静态初始化块 他们到底有什么区别呢?今天就浅谈一下JAVA中静态初始化块和非静态初始化块的区别 静态初始化块 定义: ...
- 《Java程序员面试笔试宝典》之Java程序初始化的顺序是怎样的
在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下三原则优 ...
- [java] java中的初始化顺序
先看程序: package init_cls; class A{ {System.out.println("i am in the class A!");} static { Sy ...
- 《Java程序猿面试笔试宝典》之Java程序初始化的顺序是如何的
在Java语言中.当实例化对象时.对象所在类的全部成员变量首先要进行初始化,仅仅有当全部类成员完毕初始化后,才会调用对象所在类的构造函数创建对象. Java程序的初始化一般遵循以下三个原则(以下 ...
随机推荐
- pthread_mutexattr_t设置的相关函数及其说明
基本概述 该函数用于C函数的多线程编程中,互斥锁的初始化. 头文件:#include <pthread.h> 函数原型: int pthread_mutex_init(pthread_mu ...
- 通过 Spring Session 实现新一代的 Session 管理
长期以来,session 管理就是企业级 Java 中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原 ...
- Python基础 第6章 抽象
1. 引言及抽象和结构 生成斐波那契数列的代码如下: fibs = [0, 1] num = int(input('How many num you want:')) for x in range(n ...
- 1267: 展开字符串(Java)
WUSTOJ 1267: 展开字符串 参考 jamesMusk的博客--Java 判断字符是大写小写或者数字 Description 给三个参数a1,a2,a3和一个字符串,请按以下要求展开该字符 ...
- 2019杭电多校一 A. Blank (dp)
大意: 长为$n$的数组, 每个位置范围$[0,3]$, $m$个限制$(l,r,x)$表示$[l,r]$内有$x$种数, 求方案数. 维护每个数字最后一次出现位置, 暴力$DP$ 实现时有个技巧是把 ...
- mysql常见内置函数
在mysql中有许多内置的函数,虽然功能都能在PHP代码中实现,但巧妙的应用mysql内置函数可以大大的简化开发过程,提高效率. 在这里我总结一下一些常用的,方便以后查看: mysql字符串函数: c ...
- C# LoadXml System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
去掉BOM头 writer = new XmlTextWriter(stream, new UnicodeEncoding(false,false)); 如果是UTF8 writer = new Xm ...
- python03-break、continue、for循环、数据bytes类型、字符串与字节的关系、变量指向与深浅拷贝、set集合、文件操作
目录: 1.break.continue 2.for循环 3.数据bytes类型 4.字符串与字节的关系 5.变量指向与深浅拷贝 6.set集合 7.文件操作 一.break.continue bre ...
- Spring Boot 多个域名指向同一IP
一.需求:直接通过域名访问首页(同一应用下,多个首页,包括PC端.手机端首页) 方法:采用多个域名绑定同一IP下同一应用,不同域名对应不同产品(PC.手机端)的方法,在后台通过拦截器判断 reques ...
- sql 基础语句
一.基础 2 31.说明:创建数据库 4Create DATABASE database-name 5 62.说明:删除数据库 7drop database dbname 8 93.说 ...