java反射

来源:互联网 发布:缺德的医生 知乎 编辑:程序博客网 时间:2024/06/04 00:26

许多java对象在运行时表现出两种状态:编译时类型和运行时类型。例如:Person p = new Student();

为了解决这个问题,需要知道该对象运行时类型的方法。

第一种做法是假设在编译时和运行时完全知道类型的真实信息,这就可以用instanceof进行判断,然后利用强制类型转换将其转换成其运行时类型的变量。

第二种做法是编译时完全不知道这个对象可能属于哪些类,这时就必须要利用反射。


要获得Class对象,通常用下面三种方式:

1、Class类的静态方法,Class.forName()
2、类的class属性,Person.class
3、通过对象的getClass()方法。这个方法是java.lang.Object类中的方法。
1、2都是通过类来获取的,一般情况下用第二种比较好,直接调用属性。但是当程序只能获取到字符串如”java.lang.String”时,就只能用第一种了。

获得某个类对应的Class对象后,就可以调用Class对象的方法来获得该对象和该类的真实信息了,如类包含的构造器、方法、成员变量、Annotation、内部类、接口、继承的父类、修饰符、所在包、类名等等。


使用反射来生成对象有两种方式:

1,使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该对象的对应类有默认构造器。

2,先使用Class对象获取指定的Construtor对象,再调用Construtor对象的newInstance()方法来创建该Class对象对应类的实例。


使用反射调用方法:

获得类对应的Class对象后,可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或者指定方法,返回Method数组或者对象。

在Method中包含一个invoke()方法:public Object invoke(Object obj, Object... args),其中obj是执行该方法的主调,后面的args是传入的实参。


使用反射访问成员变量:

getField(String name)获取指定名称的public成员变量

getDeclaredField(String name)获取指定名称的成员变量,与访问权限无关。

Field提供了两组方法来读取或者设置成员变量值:

getXxx(Object obj),获取成员变量值,这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消get后面的Xxx。

setXxx(Object obj),设置成员变量值,这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消set后面的Xxx。


使用反射操作数组:

newInstance(Class<?> componentType, int... dimensions)创建一个指定元素类型,指定维度的新数组。

getXxx(Object array, int index) 这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消get后面的Xxx。

setFloat(Object array, int index, Xxx f) 这里Xxx对应8种基本类型,如果该成员变量是引用类型,则取消set后面的Xxx。

注意这些方法都是java.lang.reflect.Array的静态方法


如果在程序中为一个或多个接口动态生成实现类或创建实例,都可以使用Proxy生成动态代理。


使用泛型可以避免强制类型转换,下面代码在编译时不会发生错误,但是在运行时抛出异常:

public static Object getInstance(String clsName){try{// 创建指定类对应的Class对象Class cls = Class.forName(clsName);// 返回使用该Class对象所创建的实例return cls.newInstance();}catch(Exception e){e.printStackTrace();return null;}}
但是如果改成下面这样,就不会发生了:

public class CrazyitObjectFactory2{public static <T> T getInstance(Class<T> cls){try{return cls.newInstance();}catch(Exception e){e.printStackTrace();return null;}}public static void main(String[] args){// 获取实例后无须类型转换Date d = CrazyitObjectFactory2.getInstance(Date.class);JFrame f = CrazyitObjectFactory2.getInstance(JFrame.class);}}

使用反射来获取泛型信息:

public class GenericTest{private Map<String , Integer> score;public static void main(String[] args)throws Exception{Class<GenericTest> clazz = GenericTest.class;Field f = clazz.getDeclaredField("score");// 直接使用getType()取出的类型只对普通类型的成员变量有效Class<?> a = f.getType();// 下面将看到仅输出java.util.MapSystem.out.println("score的类型是:" + a);// 获得成员变量f的泛型类型Type gType = f.getGenericType();// 如果gType类型是ParameterizedType对象if(gType instanceof ParameterizedType){// 强制类型转换ParameterizedType pType = (ParameterizedType)gType;// 获取没有泛型信息的原始类型Type rType = pType.getRawType();System.out.println("原始类型是:" + rType);// 取得泛型参数的类型Type[] tArgs = pType.getActualTypeArguments();System.out.println("泛型信息是:");for (int i = 0; i < tArgs.length; i++){System.out.println("第" + i + "个泛型类型是:" + tArgs[i]);}}else{System.out.println("获取泛型类型出错!");}}}



0 0
原创粉丝点击