日期:2014-05-20  浏览次数:20973 次

Java反射中构造函数的顺序问题
有如下代码
Java code

package com.hzt;

import java.lang.reflect.Constructor;

class Person{
     
    public Person() {
         
    }
    public Person(String name){
        this.name=name;
    }
    public Person(int age){
        this.age=age;
    }
    public Person(String name, int age) {
        this.age=age;
        this.name=name;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    @Override
    public String toString(){
        return "["+this.name+"  "+this.age+"]";
    }
    private String name;
    private int age;
}
 
class hello{
    public static void main(String[] args) {
        Class<?> demo=null;
        try{
            demo=Class.forName("com.hzt.Person");
        }catch (Exception e) {
            e.printStackTrace();
        }
        Person per1=null;
        Person per2=null;
        Person per3=null;
        Person per4=null;
        //取得全部的构造函数
        Constructor<?> cons[]=demo.getConstructors();
        try{
            per1=(Person)cons[2].newInstance();
            per2=(Person)cons[3].newInstance("Rollen");
            per3=(Person)cons[1].newInstance(20);
            per4=(Person)cons[0].newInstance("Rollen",20);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(per1);
        System.out.println(per2);
        System.out.println(per3);
        System.out.println(per4);
    }
}


反射调用其构造函数的时候,发现cons[]数组中的顺序无法确定,如果是直接run的话,顺序是 2 3 1 0,但是如果是debug的话,那么顺序就是 3 2 1 0。
使用getConstructors()函数时,返回的构造函数的顺序如何确定?为什么在debug和run的顺序还不同?
谢谢!

------解决方案--------------------
不要这样,用指定的构造方法:

Java code
public static void main(String[] args) {
        Class<?> demo = null;
        try {
            demo = Class.forName("com.hzt.Person");
            Constructor cons0 = demo.getConstructor();
            Constructor cons1 = demo.getConstructor(String.class);
            Constructor cons2 = demo.getConstructor(int.class);
            Constructor cons3 = demo.getConstructor(String.class,int.class);
            
            Person per1 = (Person) cons0.newInstance();
            Person per2 = (Person) cons1.newInstance("Rollen");
            Person per3 = (Person) cons2.newInstance(20);
            Person per4 = (Person) cons3.newInstance("Rollen", 20);
            
            System.out.println(per1);
            System.out.println(per2);
            System.out.println(per3);
            System.out.println(per4);
        }
        catch (Exception e) {
            e.printStackTrace();
        }        
    }

------解决方案--------------------
探讨

我看了Class 的代码, 第一次取得getConstructors还是掉native函数的。
我猜测还是读.class文件来分析出来的。
所以最可能是的构造函数在.class文件里的顺序。

也许debug和run的class文件不一样? hoho。 随便猜猜。

------解决方案--------------------
C/C++ code

JNIEXPORT jobjectArray JNICALL
 JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly) {
-  NYI();
+  ArrayObject* ret = 0;
+  JavaObject* tmp = 0;
+  JavaObject* Cl = 0;
+  llvm_gcroot(Cl, 0);
+  llvm_gcroot(ret, 0);
+  llvm_gcroot(tmp, 0);
+
+  BEGIN_JNI_EXCEPTION
+
+  Cl = *(JavaObject**)ofClass;
+
+  Jnjvm* vm = JavaThread::get()->getJVM();
+  UserCommonClass* cl = UserCommonClass::resolvedImplClass(vm, Cl, false);
+
+  if (cl->isArray() || cl->isInterface() || cl->isPrimitive()) {
+    ret = (ArrayObject*)vm->upcalls->constructorArrayClass->doNew(0, vm);
+  } else {
+    UserClass* realCl = cl->asClass();;
+    JnjvmClassLoader* classLoader = cl->classLoader;
+    uint32 size = 0;
+
+    for (uint32 i = 0; i < realCl->nbVirtualMethods; ++i) {
+      JavaMethod* meth = &realCl->virtualMethods[i];
+      bool pub = isPublic(meth->access);
+      if (meth->name->equals(classLoader->bootstrapLoader->initName) &&
+          (!publicOnly || pub)) {
+        ++size;
+      }
+    }
+
+    ret = (ArrayObject*)vm->upcalls->constructorArrayClass->doNew(size, vm);
+
+    sint32 index = 0;
+    for (uint32 i = 0; i < realCl->nbVirtualMethods; ++i) {
+      JavaMethod* meth = &realCl->virtualMethods[i];
+      bool pub = isPublic(meth->access);
+      if (meth->name->equals(classLoader->bootstrapLoader->initName) &&
+          (!publicOnly || pub)) {
+        UserClass* Cons = vm->upcalls->newConstructor;
+        JavaObject * pArr = meth->getParameterTypes(classLoader);
+        JavaObject * eArr = meth->getExceptionTypes(classLoader);
+        tmp = Cons->doNew(vm);
+        vm->upcalls->initConstructor->invokeIntSpecial(vm, Cons, tmp,
+          &Cl,          /* declaringClass */
+          &pArr,        /* parameterTypes */
+          &eArr,        /* checkedExceptions */
+          meth->access, /* modifiers */
+          i,            /* slot */
+          NULL,         /* String signature */
+          NULL,         /* annotations */
+          NULL          /* parameterAnnotations */
+        );
+        ArrayObject::setElement(ret, tmp, index);
+        index++;
+      }
+    }
+  }
+
+  RETURN_FROM_JNI((jobjectArray)th->pushJNIRef(ret));
+
+  END_JNI_EXCEPTION
+
+  return 0;
 }