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的方法,它就是我们的构造函数, ...
随机推荐
- 「JSOI2018」战争
「JSOI2018」战争 解题思路 我们需要每次求给一个凸包加上一个向量后是否与另外一个凸包相交,也就是说是否存在 \[ b\in B,(b+w)\in A \] 这里 \(A, B\) 表示凸包内部 ...
- luoguP4466 [国际集训队]和与积 莫比乌斯反演
自然想到枚举\(gcd(a, b)\),不妨设其为\(d\),并且\(a = di, b = dj(a > b)\) 那么\(\frac{ab}{a + b} = \frac{dij}{i + ...
- bzoj4399 魔法少女LJJ 线段树合并
只看题面绝对做不出系列.... 注意到\(c \leqslant 7\),因此不会有删边操作(那样例删边干嘛) 注意到\(2, 5\)操作十分的有趣,启示我们拿线段树合并来做 操作\(7\)很好处理 ...
- Illegal instruction错误的定位---忽略编译期警告的代价
在原计算机的linux c++程序可以正确跑起来,但是换了一台机器运行时出现致命错误,程序直接当掉,错误提示如下: Illegal instruction (core dumped) 造成改错的主要原 ...
- jquery 图片预加载
/图片无序预加载 (function($){ function Preload(imgs,fns){ this.imgs=(typeof imgs==="string")?[img ...
- windows下git命令的使用
一.写在前面 关于git,出于自己的爱好,前段时间玩了一下,也自己上网查了一下资料,现简单记录一下,以备查看. 当然,本文并不是介绍配置git服务器的文章,而是以github服务器作为git的远程仓库 ...
- ansible saltstart puppet
百台以下用ansible , 百台-千台用saltstart , 千台以上用puppet
- QT 安装 4.8.7 on solaris 10
1. 下载 QT 4.8.7: http://download.qt.io/official_releases/qt/4.8/4.8.7/qt-everywhere-opensource-src-4 ...
- linux umask命令
umask命令 umask命令功能:显示.设置文件的缺省权限. umask命令语法:umask [-S] -S:以rwx形式显示新建文件或目录的缺省权限. 执行umask: 显示0022 第一个0:特 ...
- 论DELPHI跨平台中间件的策略
论DELPH跨平台中间件的策略 1)起先DELPHI只支持WINDOWS,此时DELPHI三层开发的眼里只有WINDOWS COM. 基于WINDOWS COM的OleVariant组合拳=TData ...