Java反射机制

来源:互联网 发布:java 日期相差天数 编辑:程序博客网 时间:2024/06/10 13:51

反射,又是个听起来挺高大上的东西啊~

我们知道在Java中有句至理名言,万事万物皆对象,当 A a = new A();的时候,有没有想过这个A是什么类型的?我在这里理解为它是Class类型,那要如何拿到Class对象呢,介绍三种方法:

1...Class c = A.class;//这个能拿到class对象说明在Class中是有个静态成员的class

2...Class c = new A().getClass();

3...Class c = Class.forName("com.xxx.A");//参数要完整的包名路径

通过上面方法就能拿到Class对象了,那比如A类里面有个方法,我要如何调用?这当然要拿到A对象实例了,如何拿?

A a = (A)c.newInstance();//newInstance()返回的Object对象,需要转成A才能调用A的方法,而且要求A类中有无参构造器,这个会调用无参构造方法,还要捕获异常。

类加载分为静态加载和动态加载,我们常用的new方式就属于静态加载,这种加载的弊端就是如果我们要加载的类是不存在的,那编译无法通过。但是有个问题,我们程序执行中并不一定必须要new出这个不存在的对象,比如说程序中我们控制在某条件下new:

int num = 1;

if(num == 0){ A a = new A();} else if(num == 1){B b = new B();}//没有A类有B类

这个例子可能比较极端,反正大概就这么个意思,有时候A对象可能并不是每次都需要的,但这时是无法通过编译,更不能执行了

所以动态加载就可以解决这种问题。首先可以定义一个接口IFace,让我们的类B继承这个接口,再用Class.forName();能拿到Class对象,如果参数传"com.xxx.A",A不存在的话这里运行时会抛异常,但并不会导致无法编译,而且此时是不影响我们对B对象的使用,想使用B的方法那就可以c=Class.forName("com.xxx.B")拿到B的class对象再IFace instance = (IFace)c.newInstance();来调用;当要有个D类的时候就可以让D去实现IFace接口,已同样的方式调用D的方法了。简单打下代码

Interface IFace{ void eat();}

class B implements IFace{ void eat("B eat");}

class MyStart{ main...(){try{ Class c = Class.forName("com.xxx.B");IFace iface = (IFace)c.newInstance();iface.eat();}catch(...){...} }}

反射有一些常用的方法,比如获取类的信息:

Method[] methods = c.getMethods();//获取所有public函数,包括从父类继承而来的方法

Method[] dMethods = c.getDeclaredMethods();//获取该类自己的方法

method.getReturnType().getName();//获取某方法返回值类型的类型

method.getName();//获取方法名

method.getParameterTypes();//参数的class数组 ,调用其getName就能获取参数类型了

Method method = c.getMethod("append",new Class[]{String.class,String.class});

Object obj = method.invoke(c,new Object[]{"abc","def"});//调用两个String参数的方法并传入参数

Object obj = method.invoke(c,"abc","def");//和上面一样,因为参数是可变参数嘛,这么写也可以

成员变量:

Field[] fields = c.getFields();//获取所有public成员变量

Field[] dFields = c.getDeclaredFields();//获取该类自己声明的成员变量,包括私有

Field field = c.getDeclaredField("xxx");//获取某个成员变量

field.set(c,"");//可给其赋值,但私有的需要设置accessible,否则抛出异常

fieldAge.setAccessible(true);// 打破封装,可访问私有

field.getType().getName();//获取成员变量类型

field.getName();//成员变量名称

Modifier.toString(field.getModifiers());//获取修饰符


构造方法:

Constructor[] constructors = c2.getConstructors();//获取所有public的构造方法

Constructor[] constructors = c2.getDeclaredConstructors();//获取所有自定义的构造方法

Constructor constructor = c2.getDeclaredConstructor(String.class);//获取对应参数的构造方法,参数为可变参数

constructor.getParameterTypes();//构造函数参数类型列表,getName获取参数类型


反射还有一个不知道有什么作用的作用,比如一个存放int类型的集合,它的泛型是int,我们可以用反射给这个集合中加入其它类型的数据,比如String类型,因为泛型只是一种类似于编译时的检查机制,在运行时是不存在泛型这个概念的,所以可以用反射跳过编译错误成功加到集合中,而且对于两个不同泛型的集合,他们的class是相同的~

0 0