有如下代码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的顺序还不同?
谢谢!

解决方案 »

  1.   

    不要这样,用指定的构造方法: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();
    }
    }
      

  2.   

    API并没有说要以什么顺序返回
      

  3.   

    我看了Class 的代码, 第一次取得getConstructors还是掉native函数的。
    我猜测还是读.class文件来分析出来的。 
    所以最可能是的构造函数在.class文件里的顺序。 也许debug和run的class文件不一样? hoho。 随便猜猜。
      

  4.   

    我试下来顺序是一致的,不管是run还是debug,都是按照constructor声明的顺序排列,换了一下constructor顺序,也是按照声明顺序。
    用的是jdk1.6.0_24
      

  5.   

    我的JDK版本是 1.7.0_05-b05
    构造函数顺序修改后,虽然下面调用的顺序也会改,但是也还不是按照声明顺序的
      

  6.   

    你换下1.6看看,我换成1.7之后照样是声明顺序,但如果再增加一个constructor的话,顺序就乱了。如果可以看到native方法,getDeclaredConstrtuctors0
      

  7.   

    public class com.hzt.Hello extends java.lang.Object{
    public com.hzt.Hello();
      Code:
       0:   aload_0
       1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
       4:   returnpublic static void main(java.lang.String[]);
      Code:
       0:   aconst_null
       1:   astore_1
       2:   ldc     #16; //String com.hzt.Person
       4:   invokestatic    #18; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/la
       7:   astore_1
       8:   goto    16
       11:  astore_2
       12:  aload_2
       13:  invokevirtual   #24; //Method java/lang/Exception.printStackTrace:()V
       16:  aload_1
       17:  invokevirtual   #29; //Method java/lang/Class.getConstructors:()[Ljava/lang/reflec
       20:  astore_2
       21:  getstatic       #33; //Field java/lang/System.out:Ljava/io/PrintStream;
       24:  aload_2
       25:  iconst_0
       26:  aaload
       27:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       30:  getstatic       #33; //Field java/lang/System.out:Ljava/io/PrintStream;
       33:  aload_2
       34:  iconst_1
       35:  aaload
       36:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       39:  getstatic       #33; //Field java/lang/System.out:Ljava/io/PrintStream;
       42:  aload_2
       43:  iconst_2
       44:  aaload
       45:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       48:  getstatic       #33; //Field java/lang/System.out:Ljava/io/PrintStream;
       51:  aload_2
       52:  iconst_3
       53:  aaload
       54:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       57:  getstatic       #33; //Field java/lang/System.out:Ljava/io/PrintStream;
       60:  aload_2
       61:  iconst_4
       62:  aaload
       63:  invokevirtual   #39; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
       66:  return
      Exception table:
       from   to  target type
         2     8    11   Class java/lang/Exception
    } 如果從assembly code角度看,貌似看不出什麼結果
      

  8.   


    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;
     }
    https://llvm.org/viewvc/llvm-project/vmkit/trunk/lib/J3/ClassLib/OpenJDK/OpenJDK.inc?r1=143672&r2=143671&pathrev=143672
      

  9.   

    无需关心顺序
    如果是指定了参数类型列表,那么你必然知道如何传入参数
    如果是直接获取构造数组,那么你在遍历的时候,可以通过getParameterTypes来获得参数类型列表
    然后就可以继续做了送LZ一句话:不要去关心不需要你关心的东西~
      

  10.   

    public Constructor<?>[] getDeclaredConstructors()
                                             throws SecurityException
    Returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object. These are public, protected, default (package) access, and private constructors. The elements in the array returned are not sorted and are not in any particular order. If the class has a default constructor, it is included in the returned array. This method returns an array of length 0 if this Class object represents an interface, a primitive type, an array class, or void. 
    See The Java Language Specification, section 8.2. 
    getConstructors() 和 getDeclaredConstructors 应该是彼此间重用了的。
    api说明了返回无特定顺序,代码也没有直接表明是按某特定顺序。
      

  11.   

    返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序
      

  12.   

    返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序
      

  13.   

    返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序
      

  14.   

    他可能认为方法声明顺序没有实际使用意义 and/or 实现排序返回也有一定代价