`
RednaxelaFX
  • 浏览: 3013892 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

实例构造器是不是静态方法?

阅读更多
如题。这个问题的答案要看你心中的“静态”指代了什么。

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

想起以前在JavaEye问答频道见过的类似问题,看来这“静态”有一定迷惑性的。

在Java中,“static”可以有多个意思,对方法而言,至少包括下面两点:
1、Java语言中的“static”关键字用于修饰方法时,表示“静态方法”,与“实例方法”相对。
2、在讨论方法的具体调用目标时,一个方法调用到底能否在运行前就确定一个固定的目标,是则可以进行“静态绑定”(static binding),否则需要做“运行时绑定”(runtime binding)。这与“static”关键字不是一回事。

===========================================================================

先看看第一点,Java语言中的“static“关键字修饰的方法。

根据Java语言规范第三版,静态方法的规定为:
Java Language Specification, 3rd 写道
8.4.3.2 static Methods

A method that is declared static is called a class method. A class method is always invoked without reference to a particular object. An attempt to reference the current object using the keyword this or the keyword super or to reference the type parameters of any surrounding declaration in the body of a class method results in a compile-time error. It is a compile-time error for a static method to be declared abstract.

A method that is not declared static is called an instance method, and sometimes called a non-static method. An instance method is always invoked with respect to an object, which becomes the current object to which the keywords this and super refer during execution of the method body.

注意到规范中关于“静态方法”(红色部分)与“实例方法”(蓝色部分)的定义。两者的关键差异在于:“静态方法”的调用总是不指定某个对象实例为“接收者”,而“实例方法”则总是要以某个对象实例为“接收者”(receiver)。

用Java的语法来演示。

调用实例方法,从调用者的一方看,“接收者”就是“点”之前的那个变量所引用的对象:
receiver.instanceMethod(args)

如果一个被被调用者与调用者在同一个类中,那么receiver可以省略不写,由编译器判断出“接收者”是this。

从被调用的一方看,“接收者”就是在方法中可以使用的伪变量“this”:
public void instanceMethod(Object... args) {
    // 注意“this”
    System.out.println(this);
}

“this”并没有出现在参数列表中,但它实际上做作为实例方法调用的一个隐式参数传入的。

调用静态方法则不需要、无法指定也无法使用receiver。Java语言中的类不是对象,所以通过ClassName.aStaticMethod(args)的方式去调用一个静态方法时,“点”前面的并不是receiver。如果“点”前面的是一个指向某对象实例的变量而“点”后面指定的是一个静态方法,则实际上那个变量并没有被作为receiver使用,只是个调用变量的类型上声明的静态方法的语法糖而已。也就是说:
aVariable.aStaticMethod(args)

实际上等效于:
TheClass.aStaticMethod(args)


关于“this”的规定,Java语言规范第三版如是说:
Java Language Specification, 3rd 写道
15.8.3 this

The keyword this may be used only in the body of an instance method, instance initializer or constructor, or in the initializer of an instance variable of a class. If it appears anywhere else, a compile-time error occurs.

很明显,在构造器中是可以访问“this”的;实例初始化器与实例变量初始化器在编译时会与构造器一起被收集到<init>()方法中,它们也都可以访问“this”。所以从Java语言的“static”关键字的角度看,实例构造器不是“静态方法”。

-------------------------------------------

Java语言通常是编译为class文件后由Java虚拟机来运行的。在Java虚拟机规范第二版中,有这样的描述:
Java virtual machine specification, 2nd 写道
3.6.1 Local Variables

Each frame (§3.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile time and supplied in the binary representation of a class or interface along with the code for the method associated with the frame (§4.7.3).
A single local variable can hold a value of type boolean, byte, char, short, int, float, reference, or returnAddress. A pair of local variables can hold a value of type long or double.

Local variables are addressed by indexing. The index of the first local variable is zero. An integer is be considered to be an index into the local variable array if and only if that integer is between zero and one less than the size of the local variable array.

A value of type long or type double occupies two consecutive local variables. Such a value may only be addressed using the lesser index. For example, a value of type double stored in the local variable array at index n actually occupies the local variables with indices n and n +1; however, the local variable at index n +1 cannot be loaded from. It can be stored into. However, doing so invalidates the contents of local variable n.

The Java virtual machine does not require n to be even. In intuitive terms, values of types double and long need not be 64-bit aligned in the local variables array. Implementors are free to decide the appropriate way to represent such values using the two local variables reserved for the value.

The Java virtual machine uses local variables to pass parameters on method invocation. On class method invocation any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

3.6.1小节的最后一段提到了“类方法”(“静态方法”)与“实例方法”在概念中的JVM上的区别:在调用类方法时,所有参数按顺序存放于被调用方法的局部变量区中的连续区域,从局部变量0开始;在调用实例方法时,局部变量0用于存放传入的该方法所属的对象实例(Java语言中的“this”),所有参数从局部变量1开始存放在局部变量区的连续区域中。
从效果上看,这就等于在调用实例方法时总是把“this”作为第一个参数传入被调用方法。

在关于方法描述符的部分:
Java virtual machine specification, 2nd 写道
4.3.3 Method Descriptors

(... 省略)

For example, the method descriptor for the method

    Object mymethod(int i, double d, Thread t)
is
    (IDLjava/lang/Thread;)Ljava/lang/Object;
Note that internal forms of the fully qualified names of Thread and Object are used in the method descriptor.
The method descriptor for mymethod is the same whether mymethod is a class or an instance method. Although an instance method is passed this, a reference to the current class instance, in addition to its intended parameters, that fact is not reflected in the method descriptor. (A reference to this is not passed to a class method.) The reference to this is passed implicitly by the method invocation instructions of the Java virtual machine used to invoke instance methods.

这里提到一个方法无论是类方法还是实例方法,其方法描述符都是一样的。“this”作为调用实例方法的一个隐式参数,不会反映在方法描述符中。

===========================================================================

接下来看第二点,关于调用方法时选择具体的目标的“static”。

Java语言中,虚方法可以通过覆写(override)的方式来实现子类型多态(subtype polymorphism)。Java语言支持三种多态,除了子类型多态外还有通过方法重载支持的ad-hoc多态(ad-hoc polymorphism)与通过泛型支持的参数化多态(parametric polymorphism)。在面向对象编程的语境里“多态”一般指子类型多态,下面提到“多态”一词也特定指子类型多态。

Java语言中非虚方法可以通过“静态绑定”(static binding)或者叫“早绑定”(early binding)来选择实际的调用目标——因为无法覆写,无法产生多态的效果,于是可能的调用目标总是固定的一个。虚方法则一般需要等到运行时根据“接收者”的具体类型来选择到底要调用哪个版本的方法,这个过程称为“运行时绑定”(runtime binding)或者叫“迟绑定”(late-binding)。
不过Java的虚方法的迟绑定具体如何去选择目标是写死在语言规范与JVM的实现中的,用户无法干涉选择的过程。这使得Java提供的迟绑定缺乏自由度。在Java 7开始提供invokedynamic支持后,用户可以自行编写程序来控制迟绑定的过程,开始对选择调用目标拥有完整的控制权。

Java语言中,哪些方法是虚方法呢?静态方法全部都是非虚的,而实例方法则看情况。
Java语言规范第三版说明了哪些实例方法不是虚方法:
Java Language Specification, 3rd 写道
8.4.3.3 final Methods

A method can be declared final to prevent subclasses from overriding or hiding it. It is a compile-time error to attempt to override or hide a final method.
A private method and all methods declared immediately within a final class (§8.1.1.2) behave as if they are final, since it is impossible to override them.

It is a compile-time error for a final method to be declared abstract.

行为如同“final”的方法都无法覆写,也就无法进行子类型多态;声明为final或private的方法都被属于这类。所以除了静态方法之外,声明为final或者private的实例方法也是非虚方法。其它实例方法都是虚方法。

Java语言规范接着提到:
Java Language Specification, 3rd 写道
8.4.3.3 final Methods

(... 省略)

At run time, a machine-code generator or optimizer can "inline" the body of a final method, replacing an invocation of the method with the code in its body. The inlining process must preserve the semantics of the method invocation. In particular, if the target of an instance method invocation is null, then a NullPointerException must be thrown even if the method is inlined. The compiler must ensure that the exception will be thrown at the correct point, so that the actual arguments to the method will be seen to have been evaluated in the correct order prior to the method invocation.

Consider the example:
final class Point {
	int x, y;
	void move(int dx, int dy) { x += dx; y += dy; }
}
class Test {
	public static void main(String[] args) {
		Point[] p = new Point[100];
		for (int i = 0; i < p.length; i++) {
			p[i] = new Point();
			p[i].move(i, p.length-1-i);
		}
	}
}

Here, inlining the method move of class Point in method main would transform the for loop to the form:
		for (int i = 0; i < p.length; i++) {
			p[i] = new Point();
			Point pi = p[i];
			int j = p.length-1-i;
			pi.x += i;
			pi.y += j;
		}

The loop might then be subject to further optimizations.

Such inlining cannot be done at compile time unless it can be guaranteed that Test and Point will always be recompiled together, so that whenever Point-and specifically its move method-changes, the code for Test.main will also be updated.

这里提到“final方法”可以在运行时得到内联。其实所有非虚方法在运行时都可以安全的被内联。
一个保守的JVM可以如上述说明一样在运行时对非虚方法的调用进行内联优化;而一个激进优化的JVM则可以更进一步,将源码中声明为虚方法、但在运行时的某个时间点可以证明(例如通过类层次分析(CHA))该方法只有一个可能的调用目标时,仍然可以将调用目标内联到调用者中。现在在桌面与服务器上的主流高性能JVM,如Oracle (Sun) HotSpot、IBM J9、Oracle (BEA) JRockit等,都会做这样的激进优化。因此在开发桌面与服务器端Java程序时没有必要为了提到性能而特意将方法声明为final的。

关于HotSpot VM对final的处理,可以参考HotSpot Internals wiki的Virtual Calls一篇
引用
It is legal for an invokevirtual bytecode to refer to a final method. A final method need not have a vtable slot allocated. This means that, after linking, an invokevirtual bytecode might in fact collapse into the equivalent of an invokestatic bytecode. The interpreter is prepared to do this.


Anders Hejlsberg曾经在多个场合提到虚方法是无法内联的(例如这个Artima的访谈);确实CLR是无法内联任何虚方法调用,但那只是CLR的实现限制而已。这点上高性能JVM比CLR要先进(且复杂)许多。

来看看Oracle/Sun JDK里的HotSpot VM是如何做初步的是否能静态绑定的:
bool methodOopDesc::can_be_statically_bound() const {
  if (is_final_method())  return true;
  return vtable_index() == nonvirtual_vtable_index;
}

也就是,如果某个Java方法是final的或者不是虚方法的话,它就可以做静态绑定。

-------------------------------------------

Java虚拟机规范第二版中定义了四种不同的字节码指令来处理Java程序中不同种类的方法的调用。包括,
· invokestatic - 用于调用类(静态)方法
· invokespecial - 用于调用实例方法,特化于super方法调用、private方法调用与构造器调用
· invokevirtual - 用于调用一般实例方法(包括声明为final但不为private的实例方法)
· invokeinterface - 用于调用接口方法

其中,invokestatic与invokespecial调用的目标必然是可以静态绑定的,因为它们都无法参与子类型多态;invokevirtual与invokeinterface的则一般需要做运行时绑定,JVM实现可以有选择的根据final或实际运行时类层次或类型反馈等信息试图进行静态绑定。

===========================================================================

那么Java中的实例构造器是不是“静态方法”呢?从Java语言规范中给出的“静态方法”的定义来看,答案是“否”——首先从Java语言规范对“方法”的定义来说,构造器根本不是“方法”;其次,实例构造器有一个隐式参数,“this”,在实例构造器中可以访问“this”,可以通过“this”访问到正在初始化的对象实例的所有实例成员。

Java语言规范中关于构造器的说明中提到:
Java Language Specification, 3rd 写道
8.8 Constructor Declarations

A constructor is used in the creation of an object that is an instance of a class:

(... 省略)

Constructor declarations are not members. They are never inherited and therefore are not subject to hiding or overriding.

实例构造器无法被隐藏或覆写,不参与多态,因而可以做静态绑定。从这个意义上可以认为实例构造器是“静态”的,但这种用法与Java语言定义的“静态方法”是两码事。

另外需要注意的是,Java语言中,实例构造器只能在new表达式(或别的构造器)中被调用,不能通过方法调用表达式来调用。new表达式作为一个整体保证了对象的创建与初始化是打包在一起进行的,不能分开进行;但实例构造器只负责对象初始化的部分,“创建对象”的部分是由new表达式本身保证的。

举个例子,下面的Java代码
public class ConstructorDemo {
    private int value;
    
    public ConstructorDemo(int i, Object o) {
        this.value = i;
    }
    
    public static void main(String[] args) {
        ConstructorDemo demo = new ConstructorDemo(2, args);
    }
}

被编译为class文件后,实例构造器与main()方法的内容分别为:
public ConstructorDemo(int, java.lang.Object);
  Code:
   Stack=2, Locals=3, Args_size=3
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   iload_1
   6:   putfield        #2; //Field value:I
   9:   return

public static void main(java.lang.String[]);
  Code:
   Stack=4, Locals=2, Args_size=1
   0:   new     #3; //class ConstructorDemo
   3:   dup
   4:   iconst_2
   5:   aload_0
   6:   invokespecial   #4; //Method "<init>":(ILjava/lang/Object;)V
   9:   astore_1
   10:  return


先从main()方法开始看。
第一条指令是new,用于创建出ConstructorDemo类型的一个空对象,执行过后指向该对象的引用被压到操作数栈上。
第二条指令是dup,将操作数栈顶的值复制一份压回到栈顶;其中dup出来的一份用于作为隐式参数传到实例构造器里去(对应后面的invokespecial),原本的一份用于保存到局部变量去(对应后面的astore_1)。
第三条指令是iconst_2,将常量2压到操作数栈上,作为ConstructorDemo实例构造器的第一个显式参数。
第四条指令是aload_0,将main()方法的参数args作为ConstructorDemo实例构造器的第二个显式参数。
第五条指令是invokespecial,调用ConstructorDemo实例构造器。再次留意,前面已经传了三个参数,分别是new出来的实例的引用、常量2与main()的参数args。该指令执行过后,操作数栈顶就只剩下dup前通过new得到的引用。
第6条指令是astore_1,将操作数栈顶的引用保存到局部变量1中。执行过后操作数栈空了。
最后一条指令是return,结束main()方法的执行并返回。

然后从ConstructorDemo的实例构造器来看。
第一条指令是aload_0,将第一个参数(不管是隐式还是显式参数)压到操作数栈上。从main()的调用序列可以看到第一个参数是刚new出来的对象实例的引用,对这个构造器来说也就是“this”。
第二条指令是invokespecial,调用Object的实例构造器。前一条指令的“this”就是这个调用的参数。执行过后操作数栈就空了。
第三条指令又是aload_0,再次将“this”压到操作数栈上。
第四条指令是iload_1,将第二个参数压到操作数栈上,也就是i。
第五条指令是putfield,将i赋值给this.value。执行过后操作数栈又空了。
最后一条指令是return,结束该实例构造器的执行并返回。

这个例子的注意点在于:
1、Java的实例构造器只负责初始化,不负责创建对象;Java虚拟机的字节码指令的设计也反映了这一点,有一个new指令专门用于创建对象实例,而调用实例构造器则使用invokespecial指令。
2、“this”是作为实例构造器的第一个实际参数传入的。



相信能区分“静态方法”与“静态绑定”中的“静态”之后,就不会再将Java中的实例构造器看作是“静态方法”了。
分享到:
评论
37 楼 ArtShell 2013-12-10  
很多问题都能在博客的文章中找到答案!
36 楼 RednaxelaFX 2011-07-21  
gooooooooa 写道
invokespecial   #4; //Method "<init>":(ILjava/lang/Object;)V 
这段是不是写错了?  参数是Object?

public ConstructorDemo(int i, Object o) { 
        this.value = i; 
    } 

不是还有个int? 

有个理解不知道对不对:
Constructor 是看不到的,而 instance initializer 就是一段初始化代码 比如
上面的 this.value = i;   ??????

你可能需要把显示放大点。签名里的两个参数的类型分别是:
I
Ljava/lang/Object;
那个I就是int。
35 楼 gooooooooa 2011-07-21  
invokespecial   #4; //Method "<init>":(ILjava/lang/Object;)V 
这段是不是写错了?  参数是Object?

public ConstructorDemo(int i, Object o) { 
        this.value = i; 
    } 

不是还有个int? 

有个理解不知道对不对:
Constructor 是看不到的,而 instance initializer 就是一段初始化代码 比如
上面的 this.value = i;   ??????
34 楼 C_J 2011-04-19  
无意中翻到zangxt的帖子,就贴出来了。
后来发现不能编辑也不能删回复的。
33 楼 C_J 2011-04-19  
4 楼 left.jessica 2010-09-26   引用
hjg1988 写道
引用

《java编程思想》中文第四版96页:

总结一下对象的创建过程,假设有个名为Dog的类:

1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成

是静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。

     这里我并没有看明白作者为什么说构造器实际上是静态方法。但是我们知道,静态方法是不能使用this的。因此,"构造器实际上也是静态方法"这点很好否定。

我的理解是,静态方法是不需要通过类的实例来调用的,而是类被加载后放在栈中的,是属于“类方法”。非静态方法是要通过类的实例才调用的,是属于 “对象方法”。从这个角度来讲,构造方法可以认为是静态的,因为在调用构造方法时必定是还未实例化的,而实例化后就不能再调用构造方法了。这样理解不知道对不对


我做了个测试程序:
Java代码  收藏代码

   1. public static void main(String[] args) { 
   2.    
   3.    try{      
   4.     Class c = Class.forName("mypackage.SK"); 
   5.     Constructor[] cc = c.getConstructors(); 
   6.     Method[] m = c.getMethods(); 
   7.  
   8.     int b = cc[0].getModifiers(); 
   9.     System.out.println(b); 
  10.     System.out.println(Integer.toHexString(b)); 
  11.     System.out.println("final:" + Modifier.isFinal(b)); 
  12.     System.out.println("public:" + Modifier.isPublic(b)); 
  13.     System.out.println("abstract:" + Modifier.isAbstract(b)); 
  14.     System.out.println("native:" + Modifier.isNative(b)); 
  15.     System.out.println("protected:" + Modifier.isProtected(b)); 
  16.     System.out.println("Static:" + Modifier.isStatic(b)); 
  17.      
  18.  
  19.    catch(ClassNotFoundException cl) { 
  20.     System.out.println("ClassNotFound"); 
  21.    }  
  22.    catch(SecurityException se) { 
  23.     System.out.println("SecurityException"); 
  24.    } 
  25.  
  26. } 

public static void main(String[] args) {
 
   try{    
    Class c = Class.forName("mypackage.SK");
    Constructor[] cc = c.getConstructors();
    Method[] m = c.getMethods();

    int b = cc[0].getModifiers();
    System.out.println(b);
    System.out.println(Integer.toHexString(b));
    System.out.println("final:" + Modifier.isFinal(b));
    System.out.println("public:" + Modifier.isPublic(b));
    System.out.println("abstract:" + Modifier.isAbstract(b));
    System.out.println("native:" + Modifier.isNative(b));
    System.out.println("protected:" + Modifier.isProtected(b));
    System.out.println("Static:" + Modifier.isStatic(b));
   

   catch(ClassNotFoundException cl) {
    System.out.println("ClassNotFound");
   }
   catch(SecurityException se) {
    System.out.println("SecurityException");
   }

}


而SK:
Java代码  收藏代码

   1. public class SK { 
   2.      
   3.     public SK(){ 
   4.          
   5.     } 
   6.  
   7. } 

public class SK {

public SK(){

}

}


结果是static:false
32 楼 RednaxelaFX 2011-02-27  
william_ai 写道
引用
2、“this”是作为实例构造器的第一个实际参数传入的。

在JVM标准2中也有介绍。(实例的初始化方法也是实例的方法)
引用
On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language)


嗯这段在上面的原文里也引用过了,3.6.1的蓝字。
31 楼 william_ai 2011-02-27  
在JVM标准2中,也明确指出了
引用
A constructor cannot be abstract, static, final, native, or synchronized.
30 楼 william_ai 2011-02-27  
实例的构造方法,理解成实例的初始化方法,就不会有那么绕了。(JVM标准2中也是这么介绍的。)

抛一个问题,类和接口的初始化方法是不是static的?什么时候调用?

引用
2、“this”是作为实例构造器的第一个实际参数传入的。

在JVM标准2中也有介绍。(实例的初始化方法也是实例的方法)
引用
On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language)

29 楼 RednaxelaFX 2011-02-25  
lostdog 写道
换个角度,从jvm内部看,方法是被保存在JTOC还是TIB中,<init>被保存在JTOC中,也可以认为是静态的。

JTOC和TIB都是Jikes RVM/MRP才使用的叫法。别的JVM实现也不叫这个…
28 楼 lostdog 2011-02-25  
换个角度,从jvm内部看,方法是被保存在JTOC还是TIB中,<init>被保存在JTOC中,也可以认为是静态的。
27 楼 rjhw 2011-02-11  
rjhw 写道
实例初始化器与实例变量初始化器在编译时会与构造器一起被收集到<init>()方法中


这是你文章中的一句话 
在jvm中对构造器方法中通过使用
aload_0和invokespecial方法来调用
<init>方法
从而和你说的这句话有矛盾

不好意思 我看错了  没 问题
26 楼 rjhw 2011-02-11  
实例初始化器与实例变量初始化器在编译时会与构造器一起被收集到<init>()方法中


这是你文章中的一句话 
在jvm中对构造器方法中通过使用
aload_0和invokespecial方法来调用
<init>方法
从而和你说的这句话有矛盾
25 楼 RednaxelaFX 2010-12-23  
cantellow 写道
我英语不好,咋办?

学。

当然也可以指望别人。毕玄 @bluedavy 有向刘总编 @turingbook 建议引进这本书。如果有人翻译的话就可以坐等中文版了。但我仍然强烈推荐阅读第一手资料。
24 楼 cantellow 2010-12-23  
RednaxelaFX 写道
cantellow 写道
另,关于JVM,楼主还有什么好书推荐。

Oracle JRockit: The Definitive Guide

我英语不好,咋办?
23 楼 cantellow 2010-12-23  
我来揣测一下Bruce Eckel当初是怎么把构造器理解成为静态的。
当时sun实现构造器就是为了给开发人员初始化变量的一种手段,可能其中某些特性与静态方法符合,比如无法覆盖,不参与多态等等,所以他就认为构造器是静态方法。
其实严格来说,构造器存在于静态方法,实例方法之外的第三种方法,它会被虚拟机<init>静态方法调用。

这是我的理解。
22 楼 RednaxelaFX 2010-12-23  
cantellow 写道
另,关于JVM,楼主还有什么好书推荐。

Oracle JRockit: The Definitive Guide
21 楼 cantellow 2010-12-23  
我就是当初的提问者:http://www.iteye.com/problems/14154
惭愧呀。
当初在本科时期的确是被《Thinking In Java》误导所致。
工作快一年了,想什么时候再翻翻《深入java虚拟机》看看,毕竟很多东西都忘了。
另,关于JVM,楼主还有什么好书推荐。
20 楼 ouchxp 2010-12-23  
ZangXT 写道
页码忘记了
Even though it doesn’t explicitly use the static keyword, the constructor is actually a static method. So the first time an object of type Dog is created, or the first time a static method or static field of class Dog is accessed, the Java interpreter must
locate Dog.class, which it does by searching through the classpath.

看书不仔细 所以没被误导 晕.....
19 楼 mercyblitz 2010-06-23  
RednaxelaFX 写道
mercyblitz 写道
RednaxelaFX 写道
mercyblitz 写道
构造器是用于初始化对象状态,并且隐含了this引用。


我一直在想,能不能动态地分析所有的字节码文件,从而达到多态方法的inline,毕竟所有的对象都是字节码定义的。

分析的对象不是“字节码”而是“类层次结构”;做了这个分析后,多态方法也照样可以激进内联。实际的高性能JVM中也是这么做的。


类层次结构不在字节码体现?

Class文件中字节码只用于表示代码逻辑,类层次结构是在字节码之外的元信息里记录的。例子在之前一帖的演示稿里有,有兴趣的话可以参考。


嗯,谢谢,确实不太记得了。
18 楼 RednaxelaFX 2010-06-23  
mercyblitz 写道
RednaxelaFX 写道
mercyblitz 写道
构造器是用于初始化对象状态,并且隐含了this引用。


我一直在想,能不能动态地分析所有的字节码文件,从而达到多态方法的inline,毕竟所有的对象都是字节码定义的。

分析的对象不是“字节码”而是“类层次结构”;做了这个分析后,多态方法也照样可以激进内联。实际的高性能JVM中也是这么做的。


类层次结构不在字节码体现?

Class文件中字节码只用于表示代码逻辑,类层次结构是在字节码之外的元信息里记录的。例子在之前一帖的演示稿里有,有兴趣的话可以参考。

相关推荐

    java 静态非静态 字段方法 子类父类构造_初始化顺序!

    java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...

    java 静态块实例块构造器调用

    java 静态块实例块构造器调用在继承中的调用顺序,包括代码及注释

    java静态工厂方法详细解析——使用静态工厂方法代替构造器

    对于类而言,在我们需要获取一个实例时,最传统的方法都是通过new新建一个对象,这是jvm通过调用构造函数帮我们实例化出来的对象。而静态工厂方法则是另外一种不通过new来获取一个实例的方法,我们可以通过一个类中...

    对象和构造器

    包括Class类的模板、new对象的内存分配方式、实例和静态。

    C#小知识之有趣的类型静态构造器

    主要介绍了C#小知识之有趣的类型静态构造器,本文直接给分实例代码,然后分析了C#中的这一个有趣的现象,需要的朋友可以参考下

    基于java的企业级应用开发:Bean的实例化.ppt

    实例化Bean有三种方式,分别为构造器实例化、静态工厂方式实例化和实例工厂方式实例化(其中最常用的是构造器实例化)。 2.2.1 构造器实例化 创建Web项目,导入相关Jar包; 创建名为Bean1的Java类; 创建Spring配置...

    C#高级编程_Lambda表达式和LINQ的原理和使用

    字段的初始化是在构造函数里面完成的,实例字段在实例构造器内初始化;静态字段在静态构造器初始化。 字段是与类或类的实例关联的变量。 使用 static 修饰符声明的字段定义了一个静态字段 (static field)。一个...

    java范例开发大全

    实例174 使用构造方法的重载计算课程的GPA值 287 第10章 内部类与接口(教学视频:41分钟) 290 10.1 成员内部类 290 实例175 成员内部类的使用规范 290 实例176 猜谜 292 10.2 方法内部类 294 实例177 局部内部类的...

    C#中static静态变量的用法实例

    使用 static 修饰符声明属于类型本身而不是属于特定对象的静态成员static修饰符可用于类、字段、方法、属性、运算符、事件和构造函数,但不能用于索引器、析构函数或类以外的类型   静态全局变量 定义:在全局变量...

    C#MVC实现带参数的构造注入

    C# MVC默认的实例化控制器时是调用不带参数的构造函数,但是使用castle注入进行构造注入构造函数带参。

    C#方法的总结详解

    C#方法1:实例构造器和类2:实例构造器和结构3:类型构造器4:操作符重载方法5:转换操作符方法6:扩展方法7:部分方法1:实例构造器和类构造器是允许将类型的实例初始化为良好状态的一种特殊方法,创建一个引用类型...

    java面试宝典

    java面试题型大全 ...19、构造器Constructor是否可被override? 7 20、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法? 8

    Java范例开发大全(全书源程序)

    实例174 使用构造方法的重载计算课程的GPA值 287 第10章 内部类与接口(教学视频:41分钟) 290 10.1 成员内部类 290 实例175 成员内部类的使用规范 290 实例176 猜谜 292 10.2 方法内部类 294 实例177 局部...

    java面试总结

    19、构造器Constructor是否可被override? 15 20、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法? 15 21、写clone()方法时,...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    实例005 测试XAMPP是否安装成功 11 实例006 XAMPP应用技巧 12 实例007 第2个PHP程序 13 1.3 IIS+PHP+MySQL——独立搭建PHP 开发环境 14 实例008 安装PHP 14 实例009 安装MySQL 15 实例010 安装IIS 21 实例011 第3个...

    Java经典编程源码基础例程300.zip

    实例049 构造方法的应用 72 实例050 统计图书的销售量 73 实例051 两只完全相同的宠物 74 实例052 重新计算对象的哈希码 76 实例053 使用字符串输出对象 77 实例054 Java对象的假克隆 78 实例055 Java对象的浅克隆 ...

    spring框架技术+第2天+xmind思维导图

    bean实例化三种方式:用构造器来实例化 、使用 静态工厂方法实例化 、使用实例工厂方法实例化 。总结,我们会选择第一种方式,因为spring的存在就是要消除工厂模式,因为工厂本身就会在每次调用时new出对象,只是把...

    【04-面向对象(上)】

    •构造器的重载和方法的重载一样,都是方法名相同,形参列表不相同。 •在构造器中可通过this来调用另外一个重载的构造器。 继承的特点 •Java通过关键字extends来实现,实现继承的类称为子类,被继承的...

    Java范例开发大全 (源程序)

     实例174 使用构造方法的重载计算课程的GPA值 287  第10章 内部类与接口(教学视频:41分钟) 290  10.1 成员内部类 290  实例175 成员内部类的使用规范 290  实例176 猜谜 292  10.2 方法内部类 294  ...

    java范例开发大全(pdf&源码)

    实例174 使用构造方法的重载计算课程的GPA值 287 第10章 内部类与接口(教学视频:41分钟) 290 10.1 成员内部类 290 实例175 成员内部类的使用规范 290 实例176 猜谜 292 10.2 方法内部类 294 实例177 局部内部类的...

Global site tag (gtag.js) - Google Analytics