关于Java反射机制中通过getConstructors方法获取类中全部构造方法顺序的问题
近日学习java反射机制的过程中了解到的getConstructors()方法,此方法用于取得全部构造方法,在测试过程发现了一些问题,希望与大家分享。
问题引入
以下代码用于取得Person类中的全部构造方法:
package reflectDemo01;
import java.lang.reflect.Constructor; //导入反射包
class Person{
private String name;
private int age;
public Person(String name) { //第一个构造方法
this.setName(name);
}
public Person(String name,int age) { //第二个构造方法
this.setName(name);
this.setAge(age);
}
public void setName(String name) {
this.name=name;
}
public void setAge(int age) {
this.age=age;
}
public String toString() { //覆写toString()方法
return "姓名:"+this.name+" 年龄:"+this.age;
}
}
public class ReflectDemo01 {
public static void main(String args[]) {
Class<?>c=null; //声明Class对象
try {
c=Class.forName("reflectDemo01.Person"); //实例化Class对象
} catch (ClassNotFoundException e) {
e.printStackTrace(); //处理异常
}
Constructor<?> cons[]=c.getConstructors(); //取得全部公共构造方法
for(int i=0;i<cons.length;i++) {
System.out.println(cons[i]); //循环输出
}
}
}
运行结果如下:
通过运行结果可以看到返回的对象数组中构造方法的顺序是定义的顺序
这时将定义的两个构造方法位置交换:
public Person(String name,int age) { //原第二个构造方法
this.setName(name);
this.setAge(age);
}
public Person(String name) { //原第一个构造方法
this.setName(name);
}
得到如下结果:
输出结果也交换了顺序,与定义的顺序一致。那我们是否能得出通过getConstructors()方法获取的构造方法顺序与定义顺序一致的结论呢?
此时将一个无参构造方法加入代码,:
public Person(){} //新加入的无参构造
public Person(String name,int age) { //原第二个构造方法
this.setName(name);
this.setAge(age);
}
public Person(String name) { //原第一个构造方法
this.setName(name);
}
运行结果如下:
运行结果可见输出顺序是逆序,并不是定义的顺序,再调换一下顺序:
public Person(String name) { //第一个构造方法
this.setName(name);
}
public Person(String name,int age) { //第二个构造方法
this.setName(name);
this.setAge(age);
}
public Person(){} //新加入的无参构造
再次调换顺序后的运行结果:
输出的结果仍是逆序,那到底getConstructors()方法返回结果的顺序如何?
问题引入
public Constructor<?>[] getConstructors() throws SecurityException
查看API文档后发现getConstructors()方法返回的是此类公共构造方法的 Constructor 对象数组 ,并没有对数组存储顺序的描述,于是我猜测此方法用了栈(Stack)的存储方式,最后用先进后出(FILO)的方式输出。
为了验证猜测,我向Person类中添加了一个浮点型(Float)的属性score,并增加了一个构造方法。
private String name;
private int age;
private float score;
public Person(){} //第一个无参构造
public Person(String name) { //第二个构造方法
this.setName(name);
}
public Person(String name,int age) { //第三个构造方法
this.setName(name);
this.setAge(age);
}
public Person(float score) {} //新增的第四个构造方法
运行结果:
此时无论怎么调换方法顺序,仍是逆序输出,但再次加入2个构造方法之后,顺序发生了变化:
public Person(){} // 第一个无参构造
public Person(String name) { //第二个构造方法
this.setName(name);
}
public Person(String name,int age) { //第三个构造方法
this.setName(name);
this.setAge(age);
}
public Person(float score) {} //第四个构造方法
public Person(String name,float score) {} //新增的第五个构造方法
public Person(String name,int age,float score) {} //新增的第六个构造方法
运行结果:
从运行结果可以看见输出顺序发生了变化,虽然有一定规律但并不是有序的,由此便可以得出结论。
问题结论
进一步查看API文档发现在getDeclaredConstructors()方法的描述中有这样一句话:
The elements in the array returned are not sorted and are not in any particular order.
也就是说返回数组中的元素没有排序,也没有任何特定的顺序,这样的描述同时存在于getDeclaredFields()方法和getDeclaredMethods()中。我又向Person类中加入了若干构造方法,发现分别在第3,6,13,15,27次时,输出顺序全部发生改变。由此可以得出结论:
① 在取得全部构造方法,普通方法和属性的时候,返回数组里元素的位置是完全随机的。
② 这种随机指的不是每次执行返回的结果不同,而是随着方法和属性的增加而改变返回顺序。
所以不要采用getConstructors()方法,用数组下标获取构造方法的方式初始化对象,以免以后在类中新增构造方法时出现异常。
可以采用较为安全的getConstrutor()方法指定参数类型,再通过newInstance()方法为对象初始化:
Constructor<?> con1=c.getConstructor(String.class,int.class); //指定参数类型
Person per=(Person)con1.newInstance("MaYuKang",20); //传入参数
System.out.println(per);
运行结果:
以上所有代码及运行结果均使用Eclipse编译器,JDK10.0.1版本。如有描述不当,望大家多多纠正与补充,觉得有用就点个赞呗。