关于Java反射机制中通过getConstructors()方法获取类中全部构造方法顺序的问题

关于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版本。如有描述不当,望大家多多纠正与补充,觉得有用就点个赞呗。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354