Java之对象构造过程
先来运行一段代码
- class A {
- public A() {
- init();
- }
- public void init() {
- }
- public static void main(String[] args) {
- B b = new B();
- System.out.println("终于i的值为:" + b.i + ",j的值为:" + b.j);
- }
- }
- class B extends A {
- int i;
- int j = 999;
- public void init() {
- System.out.println("此时A的构造方法正在调用此方法:i的值为:" + i + ",j的值为:" + j);
- i = 888;
- j = 111;
- }
- }
看看打印什么
- 此时A的构造方法正在调用此方法:i的值为:0,j的值为:0
- 终于i的值为:888,j的值为:999
假设感到非常吃惊,那么你对Java对象的构造过程还不熟悉。那么认真阅读本文将对你有非常大帮助。
先写个案例代码
- public class Super {
- static long time = 10;
- static Object obj = new Object();
- int width = 100;
- static {
- time = 11;
- }
- {
- width = 110;
- }
- public Super() {
- width = 120;
- }
- public static void main(String[] args) {
- Child child = new Child();
- System.out.println("Super.time:"+Super.time);
- System.out.println("Super.obj:"+Super.obj);
- System.out.println("child.width:"+child.width);
- System.out.println("Child.age:"+Child.age);
- System.out.println("Child.str:"+Child.str);
- System.out.println("child.height:"+child.height);
- }
- }
- class Child extends Super {
- static int age = 20;
- static String str = "str";
- double height = 200;
- static {
- age = 22;
- }
- {
- height = 210;
- }
- public Child() {
- height = 220;
- }
- }
打印
- Super.time:11
- Super.obj:java.lang.Object@659e0bfd
- child.width:120
- Child.age:22
- Child.str:str
- child.height:220.0
Java中一个对象的构造过程
1.用类载入器载入父类。按父类静态变量定义的顺序的为父类全部静态变量分配空间,并赋予父类静态变量默认值
- public class Super {
- static long time=10;//此时time=0
- static Object obj=new Object();//此时obj=null
2.用类载入器载入自己,按自己静态变量定义的顺序的为自己全部静态变量分配空间,并赋予自己静态变量默认值
- class Child extends Super{
- static int age=20;//此时age=0
- static String str="str";//此时str=null
3.按父类静态变量定义的顺序的为父类全部静态变量赋上定义的值
- public class Super {
- static long time=10;//此时time=10
- static Object obj=new Object();//此时obj=new Object()
4.运行父类静态代码块
- public class Super {
- static long time=10;
- static Object obj=new Object();
- int width=100;
- static{
- time=11;//静态代码块运行了。这个时候time=11
- }
5.按自己静态变量定义的顺序的为自己全部静态变量赋上定义的值
- class Child extends Super{
- static int age=20;//此时age=20
- static String str="str";//此时str="str"
6.运行自己静态代码块
- class Child extends Super{
- static int age=20;
- static String str="str";
- double height=200;
- static{
- age=22;//此时age=22
- }
7.为父类实例变量分配空间。并赋予默认值
- public class Super {
- static long time=10;
- static Object obj=new Object();
- int width=100;//此时width=0
8.为自己实例变量分配空间。并赋予默认值
- class Child extends Super{
- static int age=20;
- static String str="str";
- double height=200;//此时height=0.0
9.按父类实例变量定义的顺序的为父类全部实例变量赋上定义的值
- public class Super {
- static long time=10;
- static Object obj=new Object();
- int width=100;//此时width=100
10.运行父类的构造代码块
- public class Super {
- static long time=10;
- static Object obj=new Object();
- int width=100;
- static{
- time=11;
- }
- {
- width=110;//此时width=110
- }
11.运行父类的构造方法
- public class Super {
- static long time=10;
- static Object obj=new Object();
- int width=100;
- static{
- time=11;
- }
- {
- width=110;
- }
- public Super() {
- width=120;//此时width=120
- }
12.按自己实例变量定义的顺序的为自己全部实例变量赋上定义的值
- class Child extends Super{
- static int age=20;
- static String str="str";
- double height=200;//此时height=200.0
13.运行自己的构造代码块
- class Child extends Super{
- static int age=20;
- static String str="str";
- double height=200;
- static{
- age=22;
- }
- {
- height=210;//此时height=210.0
- }
14.运行自己的构造方法
- class Child extends Super{
- static int age=20;
- static String str="str";
- double height=200;
- static{
- age=22;
- }
- {
- height=210;
- }
- public Child() {
- height=220;//此时height=220.0
- }
对象构造完毕!
注意
1-6属于初始化静态部分,7-14属于初始化实例部分
假设一个类的静态部分已经初始化了(已经被类载入器载入了)。就不会再反复初始化静态部分,静态部分的初始化仅仅会在类载入器载入一个类的时候初始化一次
父类假设还有父类就也按照此顺序先初始化父类的父类,直到Object为止
假设运行步骤3,5,9,12赋值操作时,假设发现所赋的值的类还没有初始化,则会先初始化那个引用的类,假设引用的类还有引用的类则也依照此顺序先初始化引用类的引用类。直到所有被引用的类所有被初始化完成为止
比如:
我们在A类中定义一个B类的引用。
- public class Super {
- public static void main(String[] args) {
- new A();new B();
- }
- }
- class A{
- static B b=new B();//这句代码会导致B类会比A类先初始化完毕,也就是说B的静态属性会先赋值,静态代码块会先运行。
- static {
- System.out.println("AA");
- }
- }
- class B{
- static {
- System.out.println("BB");
- }
- }
打印:
- BB
- AA
仅仅定义一个类的引用,而没有赋值,那么不会触发一个类初始化
- public class Super {
- public static void main(String[] args) {
- new A();
- }
- }
- class A{
- static B b;
- static {
- System.out.println("AA");
- }
- }
- class B{
- static {
- System.out.println("BB");
- }
- }
打印:
- AA
仅仅有触发了主动使用才会导致所引用的类被初始化.
关于一个人在什么情况才算是主动使用请查看我的还有一篇文章:
http://blog.csdn.net/u012643122/article/details/46522345
假设一个类A的所引用的类B里又引用了类A,也就是递归引用的情况,那么会实施java消除递归机制
如
- public class Super {
- public static void main(String[] args) {
- new A();
- }
- }
- class A{
- static B b=new B();
- static {
- System.out.println("AA");
- }
- }
- class B{
- static A a=new A();
- static {
- System.out.println("BB");
- }
- }
打印
- BB
- AA
初始化引用的类时就像走一条路,java避免递归的机制就是不走之前已经走过的地方.
假设在运行3、5、9、12时。发现变量仅仅定义了引用而没有赋值操作,那么该变量将保持默认值
如:
- static long time;//保持之前所赋的默认值0
- Child child;//保持之前所赋的默认值null
特殊情况可省略的步骤
假设一个类没有父类(如Object类),则它的初始化顺序能够简化成2、5、6、8、12、13、14。
假设这个类已经被类载入器载入过了,也就是该类的静态部分已经初始化过了,那么1、2、3、4、5、6都不会运行,总的顺序能够简化为7、8、9、10、11、12、13、14。
假设这个类没有被类载入器载入,但它的父类已经被类载入器载入过了。那么总的顺序能够简化为2、5、6、7、8、9、10、11、12、13、14。
转载请标明原地址。请尊重原创,谢谢!
Java之对象构造过程的更多相关文章
- Java内存结构、类的初始化、及对象构造过程
概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...
- Java的对象初始化过程
成员变量(字段)初始化顺序 在一个类里初始化的顺序是由成员变量在类里面的定义的顺序来决定的.即使成员变量大量散布于类的各个方法定义的中间,那些成员变量仍会在调用任何方法之前得以初始化,甚至在构造函数调 ...
- Java中对象构造
构造函数 作用:在构造对象的同时初始化对象.java强制要求对象 诞生同时被初始化,保证数据安全. 调用过程和机制:①申请内存,②执行构造函数的函数体,③返回对象的引用. 特点:与类同名,无返回类型, ...
- Java基础—对象构造
1.重载 有些类有多个构造器.例如,可以如下构造一个空的StringBuilder对象: StringBuilder message = new StringBuilder(); 或者,可以指定一个初 ...
- Java中对象创建过程
本文介绍的对象创建过程仅限于普通Java对象,不包括数组和Class对象. 1.类加载检查 虚拟机遇到一条new指令时,首先去检查该指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用 ...
- 转:java实例化对象的过程
学习JAVA这门面向对象的语言,实质就是不断地创建类,并把类实例化为对象并调用方法.对于初学JAVA的人总搞清楚对象是如何实例化的,假如类之间存在继承关系,那就更糊涂了.下面我们通过两个例题来说明对象 ...
- java实例化对象的过程
总结以上内容,可以得到对象初始化过程: 1. 如果存在继承关系,就先父类后子类: 2 .如果在类内有静态变量和静态块,就先静态后非静态,最后才是构造函数: 3 .继承关系中,必须要父类初始化完成 ...
- Java中对象初始化过程
Java为对象初始化提供了多种选项. 当new一个对象的时候,对象初始化开始: 1.首先,JVM加载类(只加载一次,所以,即使多次new对象,下面的代码也只会在第一次new的时候执行一次),此时, 静 ...
- .ctor,.cctor 以及 对象的构造过程
摘要: .ctor,.cctor 以及 对象的构造过程.ctor:简述:构造函数,在类被实例化时,它会被自动调用.当C#的类被编译后,在IL代码中会出现一个名为.ctor的方法,它就是我们的构造函数, ...
随机推荐
- Template(Updating)
1.Splay (Tyvj1728) #include <bits/stdc++.h> using namespace std; ,INF=<<; ],sz[MAXN],cnt ...
- 洛谷.4238.[模板]多项式求逆(NTT)
题目链接 设多项式\(f(x)\)在模\(x^n\)下的逆元为\(g(x)\) \[f(x)g(x)\equiv 1\ (mod\ x^n)\] \[f(x)g(x)-1\equiv 0\ (mod\ ...
- 【推导】Codeforces Round #484 (Div. 2) C. Cut 'em all!
题意:给你一棵树,让你切掉尽可能多的边,使得产生的所有连通块都有偶数个结点. 对于一棵子树,如果它有奇数个结点,你再从里面怎么抠掉偶数结点的连通块,它都不会变得合法.如果它本来就有偶数个结点,那么你怎 ...
- IntelliJ IDEA代码分屏显示
- 【windows socket+HTTPserverclient】
Windows Socket+HTTPserverclient Winsock是 Windows下套接字标准. 1.HTTP协议: HTTP ...
- 使用Bootstrap 3开发响应式网站实践03,轮播下方的内容排版
通常把一些重要信息.需要重点标注的信息放在轮播的下方显示,这部分区域用到了大字体的标题.副标题以及段落文字等. <div class="row" id="bigCa ...
- javascript中的2个感叹号的用法
!!是逻辑"非非",即是在逻辑"非"的基础上再"非"一次.通过!或!!可以将很多类型转换成bool类型,再做其它判断. 应用场景:判 ...
- Windows Embedded Compact 7 开发环境搭建
第一步,我们会定制一个运行在Vitual PC上的image.要完成这个任务,你要保证你的电脑上安装了:1.Windows Virtual PC 2.Visual Studio 2008+SP1 3. ...
- 命令行编译工具NMAKE
简介 大家已经习惯于微软提供的功能强大的IDE,已经很少考虑手动编连项目了,所谓技多不压身,有空的时候还是随我一块了解一下命令行编译. C/C++/VC++程序员或有Unix/Linux编程经验应该很 ...
- ngx_lua实现登录逻辑
最近在公司做一个简单的portal,本来很简单的,只用ngx_lua就可以实现所有的业务逻辑,不需要upstream上游服务.但被要求接入公司内部的用户校验系统,说白了就是一个登录过程,只允许公司内部 ...