Java反射机制

Class类的使用

类是java.lang.Class类的对象
任何一个类都是Class的实例对象,可以通过三种方式得到其类型:
1. 类名.class
2. 该类对象.getClass()
3. Class.forName(“类的全称”) [动态加载类]

Class c1=Foo.class;//方法一

Class c2=foo.getClass();//方法二

try {
    Class c3=Class.forName("entity.Foo");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}//方法三

可以通过类的类型创建类对象实例:newInstance()方法(该类必须要有无参构造方法)

public class Foo {
    public Foo() {};// 使用newInstance方法必须要有无参构造函数
}
Foo _foo=(Foo) c1.newInstance();//使用Class的newInstance方法构造已知类对象

new:创建对象 是静态加载,在编译时刻就需要加载所有可能使用到的类
Class.forName():创建对象 是动态加载,在运行时刻加载,使用动态加载可以方便支持新类型的扩充,而已完成的类不受兄弟(继承自同一父类,或实现同一接口)类的影响

package entity;
public class Foo {
    public String 我是变量;
    public Foo() {
    };// 使用newInstance方法必须要有无参构造函数

    public void print(String parameter) {
        System.out.println("我是" + this + "类");
        System.out.println(parameter);
    }
}
package entity;
/**
 * 该类继承自Foo
 * @author sunqi
 */
public class Foo1 extends Foo {
    public Foo1() {
    };// 使用newInstance方法必须要有无参构造函数
}

在main函数中用Class.forName()可以创建出Foo1类型的对象,由其父类型指针指向

try {
    Class c=Class.forName("entity.Foo1");
    Foo foo1=(Foo)c.newInstance();//Foo1的父类型Foo指向这个对象
    foo1.print();

    Class _c=Class.forName("entity.Foo2");//Foo2类型还不存在
    Foo foo2=(Foo)_c.newInstance();
    foo2.print();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

由于Foo2类型不存在,所以Class _c=Class.forName("entity.Foo2"); 会出现ClassNotFound异常,但是不影响Foo1对象的执行
这里写图片描述
这样可以方便添加新的继承或者实现同一接口的class的编写

方法的反射

步骤:

  1. 获取类的类类型(三种方式),返回Class类型对象
  2. 通过Class类型对象的下列方法获取相关内容(中括号里是返回类型)
    • getName():类的名称 [String]
    • getSimpleName():类的名称缩写 [String]
    • getMethods():类的方法 [Methods[]]
    • getMethod(name, parameterTypes):类的指定名称和参数类型的方法 [Method]
    • getDeclaredMethods():类自己声明的方法,不问访问权限 [Methods[]]
  3. 又获得的类的方法(即Method[])的每一个元素都是一个Class类型的对象,对这些对象调用相应的方法获得每一个”Method”的相关内容(可选)
    • getName():方法的名称 [String]
    • getReturnType():方法返回值类型 [Class]
    • getParameterTypes():方法的参数类型 [Class[]]
  4. 对获取到的方法的参数类型遍历,调用其getName()方法,获得参数类型的名称(可选)
  5. 调用获得的Method对象的invoke(obj, args);
/**
 * 获取类的方法
 * @param object 类对象
 */
public static void getClassMethods(Object object){
    Class c=object.getClass();
    System.out.println("类的名称:"+c.getName());//获得类的名称
    Method[] methods=c.getMethods();//获得类的方法
    for (Method method : methods) {
        System.out.print(method.getReturnType().getSimpleName()+" ");//获得返回值类型名称
        System.out.print(method.getName()+"(");//获得方法的名称
        Class[] paramsTypes=method.getParameterTypes();//获得参数类型
        for (Class paramsType : paramsTypes) {
            System.out.print(paramsType.getName()+",");//参数类型名称
        }
        System.out.println(")");
    }
    try {
        Method method=c.getMethod("print", new Class[]{String.class});
        //或者Method method=c.getMethod("print",String.class);
        method.invoke(object, "我是参数");
    } catch (Exception e) {
        e.printStackTrace();
    } 
}

成员变量的反射

成员变量是java.lang.reflect.Field类的对象,Field类封装了关于成员变量的操作

步骤:

  1. 获取类的类类型(三种方式),返回Class类型对象
  2. 通过Class类型对象的getFields()(或getField(name))获得成员变量,返回Field
  3. 对Field对象有下列方法
    • getName():成员变量的名称 [String]
    • getType():成员变量的类型 [Class]
/**
 * 获得类的成员变量
 * @param object 类对象
 */
public static void getClassVariable(Object object){
    Class c=object.getClass();
    Field[] fields=c.getFields();
    for (Field field : fields) {
        System.out.print(field.getType().getSimpleName()+" ");//成员变量的类型名称
        System.out.println(field.getName());//成员变量的名称
    }
}

构造函数的反射

构造函数是java.lang.Constructor类的对象,Constructor类封装了关于构造函数的操作

步骤:

  1. 获取类的类类型(三种方式),返回Class类型对象
  2. 通过Class类型对象的getConstructors()(或getConstructor(parameterTypes))获得成员变量,返回Constructor
  3. 对Constructor对象有下列方法
    • getName():构造函数的名称 [String]
    • getParameterTypes():构造函数的参数类型 [Class[]]
/**
 * 获得类的构造函数
 * @param object
 */
public static void getClassConstructor(Object object){
    Class c=object.getClass();
    Constructor[] constructors=c.getConstructors();//获得构造函数数组
    for (Constructor constructor : constructors) {
        System.out.print(constructor.getName()+" ");//构造函数名称
        Class[] parameterTypes=constructor.getParameterTypes();//构造函数参数类型
        for (Class parameterType : parameterTypes) {
            System.out.println(parameterType.getSimpleName());
        }
    }
}

Java的反射可以绕过编译时报错,编译之后的集合不具有泛型,由此可以将不满足泛型的元素加到集合中去

public class Test {

    public static void main(String[] args) throws Exception {
        ArrayList a=new ArrayList();
        ArrayList<String> b=new ArrayList<String>();

        //b.add(10);编译不通过
        Class _b=b.getClass();
        Method method=_b.getMethod("add", Object.class);
        method.invoke(b, 10);
        System.out.println(b);

        System.out.println(a.getClass()==b.getClass());//a,b类型相同
    }

}

这里写图片描述
由运行结果可以看出a,b两个集合在运行中认为类型是相同的,并且通过反射的方式将整型数’10’加入到了泛型为String类型的集合中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值