分享

Java反射中构造函数的顺序问题

 忘川界 2017-07-21
 有如下代码
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的顺序还不同? 
  谢谢! 
 回复讨论(解决方案) 
 不要这样,用指定的构造方法:
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(); 
  } 
  } 
 API并没有说要以什么顺序返回 
 我看了Class 的代码, 第一次取得getConstructors还是掉native函数的。
  我猜测还是读.class文件来分析出来的。 
  所以最可能是的构造函数在.class文件里的顺序。 
  也许debug和run的class文件不一样? hoho。 随便猜猜。 
 我试下来顺序是一致的,不管是run还是debug,都是按照constructor声明的顺序排列,换了一下constructor顺序,也是按照声明顺序。
  用的是jdk1.6.0_24 
 我试下来顺序是一致的,不管是run还是debug,都是按照constructor声明的顺序排列,换了一下constructor顺序,也是按照声明顺序。
  用的是jdk1.6.0_24 
  我的JDK版本是 1.7.0_05-b05 
  构造函数顺序修改后,虽然下面调用的顺序也会改,但是也还不是按照声明顺序的 
 引用 4 楼  的回复:
  我试下来顺序是一致的,不管是run还是debug,都是按照constructor声明的顺序排列,换了一下constructor顺序,也是按照声明顺序。 
  用的是jdk1.6.0_24 
  我的JDK版本是 1.7.0_05-b05 
  构造函数顺序修改后,虽然下面调用的顺序也会改,但是也还不是按照声明顺序的 
  你换下1.6看看,我换成1.7之后照样是声明顺序,但如果再增加一个constructor的话,顺序就乱了。如果可以看到native方法,getDeclaredConstrtuctors0 
 我看了Class 的代码, 第一次取得getConstructors还是掉native函数的。
  我猜测还是读.class文件来分析出来的。 
  所以最可能是的构造函数在.class文件里的顺序。 
  也许debug和run的class文件不一样? hoho。 随便猜猜。 
  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:   return 
  public 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角度看,貌似看不出什??果 
 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:///viewvc/llvm-project/vmkit/trunk/lib/J3/ClassLib/OpenJDK/OpenJDK.inc?r1=143672&r2=143671&pathrev=143672 
 既然是用反射。。。  你怎么知道人家的构造方法是怎么定义的 
 无需关心顺序
  如果是指定了参数类型列表,那么你必然知道如何传入参数 
  如果是直接获取构造数组,那么你在遍历的时候,可以通过getParameterTypes来获得参数类型列表 
  然后就可以继续做了 
  送LZ一句话:不要去关心不需要你关心的东西~ 
 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说明了返回无特定顺序,代码也没有直接表明是按某特定顺序。 
 超类-子类顺序 
 public Constructor<?>[] getDeclaredConstructors()
  throws SecurityException 
  Returns an array of Constructor objects reflecting all the constructors declared …… 
  既然说明里说了没有任何顺序,看来是真没有顺序了 
 返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序 
 返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序 
 返回的构造器数组是不依赖于声明顺序的,这是jdk本身决定的,他就没有保证顺序 
 引用 11 楼  的回复:
  public Constructor<?>[] getDeclaredConstructors() 
  throws SecurityException 
  Returns an array of Constructor objects reflecting all the constructors declared …… 
  既然说明里说了没有任何顺序,看来是真…… 
  他可能认为方法声明顺序没有实际使用意义 and/or 实现排序返回也有一定代价 
 原来如此,学习了 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多