夯实JAVA基本之二 —— 反射(3):类内部信息获

页面导航:首页 > 软件编程 > Java编程 > 夯实JAVA基本之二 —— 反射(3):类内部信息获

夯实JAVA基本之二 —— 反射(3):类内部信息获

来源: 作者: 时间:2016-01-21 09:39 【

前言:人总会疲惫,当感觉累的时候,再坚持一下就好,再坚持一下。上两篇文章中,给大家讲了,有关类周边信息的获取方法,这篇文章中我们将深入到类的内部,看看类的构造函数

前言:人总会疲惫,当感觉累的时候,再坚持一下就好,再坚持一下。

 

上两篇文章中,给大家讲了,有关类周边信息的获取方法,这篇文章中我们将深入到类的内部,看看类的构造函数,内部变量,函数等信息的获取方法。相比而言,这篇更重要。

一、构造函数相关获取

1、获取构造函数

要获取类的构造函数,有下面几种方法:
//获取public类型的构造函数
Constructor [] getConstructors();
Constructor getConstructor(Class ... parameterTypes);

//获取所有类型的构造函数
Constructor [] getDeclaredConstructors();
Constructor getDeclaredConstructor(Class ... parameterTypes)
这四种方法中,getConstructors与getConstructor获取的是声明为public的构造函数。无法得到声明为protected,private的构造函数。而加有Declared(声明)的两个函数getDeclaredConstructors,getDeclaredConstructor能获取所有声明的构造函数,无论它是public,proctected还是private类型,都能获取到。所以这两个函数较为常用。
下面我们举个例子来看下getDeclaredConstructors和getDeclaredConstructor的用法。

(1)、getDeclaredConstructors()

Constructor [] getDeclaredConstructors();
getDeclaredConstructors()函数得到的是一个Constructor的数组;
首先,构造一个类Person:
public class Person {
    private int age;
    private String name;
    public Person(){

    }
    private Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    private Person(Integer age, String name){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
在Person类中,目前我们只关心构造函数,所以我们声明了三个构造函数,有一个无参数的构造函数,和两个有参数的构造函数。我们把无参的构造函数声明为public,另外两个都声明为private.在上面我们说过,在四个获取构造函数的方法中,只有具有Declared的两个getDeclaredXXX()的函数才能获取类中所有的函数。而另外两个只能获取声明为public的函数。下面我们就利用一个例子来获取Person类的构造函数:
//1、枚举
Class  clazz = Person.class;
Constructor [] constructors = clazz.getDeclaredConstructors();
for (Constructor item:constructors){
    Log.d(TAG,"枚举到的构造函数:"+item.toString());
}

//2、根据类型,获取指定的构造的构造函数
Constructor  constructor = clazz.getDeclaredConstructor(Integer.class, String.class);
Log.d(TAG, "指定参数得到的构造函数:"+constructor.toString());
结果如下:
\

我们先看下这两个函数的意义,然后再来讲解上面的代码:
(1)、getDeclaredConstructors()
getDeclaredConstructors()将得到所有构造函数的列表,包括声明为private,protected和public的构造函数。
然后我们通过for…each循环,得到将每个构造函数打印出来。
(2)、getDeclaredConstructor(Class … parameterTypes)
这个函数是通过指定构造函数的参数列表来得到指定构造函数的,有两点要非常注意:

parameterTypes一定要派生自Object类型的对象。无法匹配诸如Int,double,float等原如数据数据parameterTypes一定要与要得到的构造函数中的参数声明顺序、类型及个数要完全匹配,如果多一个、少一个或类型不匹配也是找不到的。这一点是极其要注意的,getDeclaredConstructor不是模糊匹配而是精确匹配!所以综合这两点,我们再回过头来看一下我们代码:

 

 

Constructor  constructor = clazz.getDeclaredConstructor(Integer.class, String.class);
在这里,我们指定匹配构造函数时,指定参数列表,这个要匹配的构造函数的第一个参数是Integer类型,第二个参数是String类型。
大家可能会怀疑了,我们这里好像有两个构造函数能匹配:
private Person(int age, String name){
    this.age = age;
    this.name = name;
}

private Person(Integer age, String name){
    this.age = age;
    this.name = name;
}
在这两个构造函数中,第一个构造函数的age类型是原始类型int,第二个构造函数的age参数类型是Integer.
那clazz.getDeclaredConstructor(Integer.class, String.class);要匹配哪个呢?
由于这里是严格匹配,所以这里必然匹配的是private Person(Integer age, String name)函数,如果我们要匹配private Person(int age, String name)要怎么办呢?那获取构造函数的方法就要这么写了:
Constructor  constructor = clazz.getDeclaredConstructor(int.class, String.class);
这里要非常提醒大家的是,不光派生自Object的类具有Class对象,原始的数据类型也是具有Class对象的。

2、Constructor系列方法之构造实例

利用Constructor的对象来构造实例时,主要是使用的是newInstance方法:
public T newInstance(Object... args);
可以看到newInstance有可以传入可变长参数,值得非常注意的是,传入的参数类型、顺序及个数都必须与当前的Constructor对象一一对应,不然就会报下面的错误:
\

 

下面我们举个例子来看下这个函数的用法:
我们同样,这个例子还是基于Person类的:

 

public class Person {
    private int age;
    private String name;
    public Person(){

    }
    private Person(int age, String name){
        this.age = age;
        this.name = name;
    }

    private Person(Integer age, String name){
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
仍然要注意的是,这里的三个构造函数,一个无参的构造函数的访问符是public,另外两个全是private!
下面来看看,如何使用newInstance来构造Person的实例:
Class  clazz = Person.class;
Constructor  constructor = clazz.getDeclaredConstructor(Integer.class, String.class);
constructor.setAccessible(true);

//构造实例一
Person person1 = (Person) constructor.newInstance(new Integer(30),new String("harvic"));
Log.d(TAG, "构造的参数为:" + person1.getName() + "  " + person1.getAge());

//构造实例二
Person person2 = (Person) constructor.newInstance(50,"qijian");
Log.d(TAG,"构造的参数为:"+person2.getName() + "  "+ person2.getAge());

//构造实例三
Person person3 = (Person) constructor.newInstance();
person3.setAge(30);
person3.setName("qijian");
Log.d(TAG,"构造的参数为:"+person3.getName() + "  "+ person3.getAge());
结果如下:
\

 

这段代码总共分为四部分:
第一部分:获取Constructor对象

 

Class  clazz = Person.class;
Constructor  constructor = clazz.getDeclaredConstructor(Integer.class, String.class);
constructor.setAccessible(true);
首先,通过getDeclaredConstructor(Integer.class, String.class)获取指定的构造函数,要得到的这个构造函数,第一个参数是Integer类型,第二个参数是String类型。
所以匹配的是下面这个构造函数:
private Person(Integer age, String name){
    this.age = age;
    this.name = name;
}
最后一句利用的是Constructor的函数setAccessible,它完整的声明是:
void setAccessible(boolean flag)
它代表的含义是,是否将任何函数或字段设置为可访问的。如果设置为true,就不管这个函数或者字段是声明为private还是public,都是可以访问的,默认情况下是false,即只有public类型是可访问的。如果没有设置setAccessible(true)的话,在使用protected或者private构造函数创建实例时,会提示:(访问拒绝)
\

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Tags:

文章评论

最 近 更 新
热 点 排 行
Js与CSS工具
代码转换工具

<