到底是怎么实例化的

到底是怎样实例化的?

 

 

昨天读到这个帖子 http://www.iteye.com/topic/650911   ·到底JVM实例化一个对象是怎样的了··

到底有没实例化Object···我 说错了大家帮我改正··到底是怎么实例化的

 

         先来段简单的程序:

 

public class Test {

	public Test(){
		System.out.println("默認構造器!!!");
	}
	public static void main(String[] args) {

		Test test=new Test();

	}

}

  当运行这个程序的时候 JVM底层到底做了些什么,实例化test的时候是怎样的一个过程了??

  javap   -c   Test 反编译这个程序,将会看到如下的指令


到底是怎么实例化的

 

 

如果不熟悉JVM指令,看到这些东西确实难以理解···很直观的看到Test默认为继承自Object这个JAVA中的超级父类,当new Test()的时候,调用Test的默认构造器,构造器其实就是一个特殊的静态的方法(这样说应该没错吧?)·


 这些指令到底是在干些什么了???

 aload_0 将第一个引用类型本地变量推送至栈顶 

invokespecial   调用超类构造方法,实例初始化方法,私有方法(调用Object类的构造方法,JAVA中为每一个类的构造方法都生成了一个实例初始化方法,这个方法被称为<init>,我们在指令中能清晰的看到)

getstatic   获取指定类的静态域,并将其值压入栈顶  (获得System类的PrintStream类型的out静态域)

ldc      将 int float 或String型常量值从常量池中推送至栈顶 (把 "默認構造器!!!"这个字符串推送至栈顶 )

invokevirtual   调用实例方法  (调用 PrintStream类的实例方法println()

return     从当前方法返回 void  

 

new  创建一个对象,并将其引用值压入栈顶  (test对象)

invokespecial   (调用Test构造方法的实例化初始方法<init>)

  astore_1 将栈顶引用型数值存入第二个本地变量 

return     从当前方法返回 void  

        类的实例化过程中,如果是多层次的继承的话的顺序是从Object开始,依次向下执行构造函数···

 

public class Test2 {

	
	public Test2(){
		System.out.println("我是頂層的構造器");
	}


}
 
public class Test1 extends Test2 {

	public Test1(){
		
		System.out.println("我是2層的構造器");
	}


}
 
public class Test extends Test1{

	public Test(){
		System.out.println("默認構造器!!!");
	}
	public static void main(String[] args) {

		Test test=new Test();

	}

}
 
结果:
我是頂層的構造器
我是2層的構造器
默認構造器!!!

 

 到底是怎么实例化的 应该并没用实例话Object吧 只是调用了构造方法吧··正如我上面说的···构造器其实就是一个特殊的静态的方法···

   并不要创建实例对象·就可以执行·····    

这个也许是我相当然吧····最近在读深入JAVA虚拟机··等我读的有点头绪了 ·再来下次说说这个吧·到底是怎么实例化的 只是最进看这虚拟机的书,看得满投雾水··看来是我自己太菜了···

 

1 楼 spyker 2010-04-24  
深入JAVA虚拟机  我也在看
也是很晕
2 楼 spyker 2010-04-24  
我觉得所谓你这么测试时完全有问题的

你这样测试 是因为你自己写了 Test的构造器
有输出
3 楼 zhxing 2010-04-25  
深入java 虚拟机,我基本看完了,看懂了大部分吧。。
主要是要多看几遍。。。

你还没怎么看完这本书,书上有写的。。。当实例化Test类的时候,实例化方法<init>()会调用父类的实例化方法。。所以父类总是在子类实例化之前实例化。。。

lz工作几年了?
4 楼 RednaxelaFX 2010-04-25  
那个……写了篇blog希望能说明“构造器其实就是一个特殊的静态的方法”这种说法的问题在什么地方,有兴趣的话请参考:http://rednaxelafx.iteye.com/blog/652719
5 楼 driftcloudy 2010-04-25  
RednaxelaFX 写道
那个……写了篇blog希望能说明“构造器其实就是一个特殊的静态的方法”这种说法的问题在什么地方,有兴趣的话请参考:http://rednaxelafx.iteye.com/blog/652719

我是来歪楼的,专门顶顶你,哈哈
6 楼 renpeng301 2010-04-26  
spyker 写道
我觉得所谓你这么测试时完全有问题的

你这样测试 是因为你自己写了 Test的构造器
有输出

          到底是怎么实例化的 我只是想更形象啊··
7 楼 renpeng301 2010-04-26  
zhxing 写道
深入java 虚拟机,我基本看完了,看懂了大部分吧。。
主要是要多看几遍。。。

你还没怎么看完这本书,书上有写的。。。当实例化Test类的时候,实例化方法<init>()会调用父类的实例化方法。。所以父类总是在子类实例化之前实例化。。。

lz工作几年了?

到底是怎么实例化的 这个话 我好像没写吧????


我啊 工作不到一年啊 菜鸟一个啊 ··莫见笑啊 ··



8 楼 renpeng301 2010-04-26  
RednaxelaFX 写道
那个……写了篇blog希望能说明“构造器其实就是一个特殊的静态的方法”这种说法的问题在什么地方,有兴趣的话请参考:http://rednaxelafx.iteye.com/blog/652719

 到底是怎么实例化的 
9 楼 AlwenS 2010-04-26  
形象地说,实例化主要做了以下几件事情.
1.加载类,因为接下来的过程需要知道诸如类大小,类成员结构等信息.
2.在堆上分配一块内存. 类的大小在第一步可以知道,类有多大,此分配的内存一般就多大(先忽略掉数据对齐,virtual table等存在).
3.执行构造函数, 此构造函数一般是经过编译器拼凑的,除了用户自定义的初始化,还包含隐式地对父构造函数的调用,聚合对象成员构造器的调用,virtual table的初始化等....
4.留下一些元信息,让jvm知道你曾经实例化过一个类....

个人理解,说地粒度也粗,随便看看~~
10 楼 wangzaixiang 2010-04-26  
AlwenS 写道
形象地说,实例化主要做了以下几件事情.
1.加载类,因为接下来的过程需要知道诸如类大小,类成员结构等信息.
2.在堆上分配一块内存. 类的大小在第一步可以知道,类有多大,此分配的内存一般就多大(先忽略掉数据对齐,virtual table等存在).
3.执行构造函数, 此构造函数一般是经过编译器拼凑的,除了用户自定义的初始化,还包含隐式地对父构造函数的调用,聚合对象成员构造器的调用,virtual table的初始化等....
4.留下一些元信息,让jvm知道你曾经实例化过一个类....

个人理解,说地粒度也粗,随便看看~~


virtual table的初始化可不是在构造函数中进行,而是在加载类的过程中完成。
11 楼 AlwenS 2010-04-26  
wangzaixiang 写道
AlwenS 写道
形象地说,实例化主要做了以下几件事情.
1.加载类,因为接下来的过程需要知道诸如类大小,类成员结构等信息.
2.在堆上分配一块内存. 类的大小在第一步可以知道,类有多大,此分配的内存一般就多大(先忽略掉数据对齐,virtual table等存在).
3.执行构造函数, 此构造函数一般是经过编译器拼凑的,除了用户自定义的初始化,还包含隐式地对父构造函数的调用,聚合对象成员构造器的调用,virtual table的初始化等....
4.留下一些元信息,让jvm知道你曾经实例化过一个类....

个人理解,说地粒度也粗,随便看看~~


virtual table的初始化可不是在构造函数中进行,而是在加载类的过程中完成。


嗯,在JAVA中,vt的内容的确应该是在类加载,甚至应该说更早的编译阶段就可以确定了.
但具体用哪个类的vt,要延迟到实例化的过程中(构造函数)才能确定。
12 楼 wangzaixiang 2010-04-26  
AlwenS 写道
wangzaixiang 写道
AlwenS 写道
形象地说,实例化主要做了以下几件事情.
1.加载类,因为接下来的过程需要知道诸如类大小,类成员结构等信息.
2.在堆上分配一块内存. 类的大小在第一步可以知道,类有多大,此分配的内存一般就多大(先忽略掉数据对齐,virtual table等存在).
3.执行构造函数, 此构造函数一般是经过编译器拼凑的,除了用户自定义的初始化,还包含隐式地对父构造函数的调用,聚合对象成员构造器的调用,virtual table的初始化等....
4.留下一些元信息,让jvm知道你曾经实例化过一个类....

个人理解,说地粒度也粗,随便看看~~


virtual table的初始化可不是在构造函数中进行,而是在加载类的过程中完成。


嗯,在JAVA中,vt的内容的确应该是在类加载,甚至应该说更早的编译阶段就可以确定了.
但具体用哪个类的vt,要延迟到实例化的过程中(构造函数)才能确定。


不妨在bytecode一级上来理解, 一个new String("hello")对应于如下的字节码:
# new java.lang.String
# dup
# invokespecial java.lang.String.<init>(java.lang.String)

因此,实例化实际上包括两部分:
# new 对应于分配对象内存
# 调用构造函数。

其实,new 这个操作是非常简单的,基本上就两个操作:
1、malloc(sizeof instance)
2. instance.classPtr = class(在Hotspot中 每个对象有一个2字的头,其中一个字就包括对class的引用)
实际上,vtable是对象class的一部分。因此,我觉得,具体要使用那个类的vt,实际上是不需要延迟的,使用的就是这个class的vt。
13 楼 AlwenS 2010-04-26  
呵呵, 你说的这句 "instance.classPtr = class(在Hotspot中 每个对象有一个2字的头,其中一个字就包括对class的引用) " 里就包含了我说的延迟语义了.

这就等于在构造函数调用的时候才把当前实例的vt指针指向具体class里的vt表.

vt的构造不需要延迟,但vt的选定肯定需要延迟,要不然多态为什么还要叫动态绑定?