java有一定动态性,使用反射可以在程序运行时借助Reflection API获得任何类的信息,并直接改变其中的属性和方法。步骤如下:
一、获得反射对象的Class对象
加载完类之后,在方法区就会生成一个class对象,这个对象包含了类的完整信息。
- Class c=Class.forName("com.fan.Person");
- Class c1=(new Person(1,"ming")).getClass();
- Class c2=Person.class;
- System.out.println(c.equals(c1));
Notations:一个类有唯一的Class对象,类的整个结构被封装在这个对象中。一个Class对象对应一个加载到JVM的.class文件。
除了上面获得Class对象的三种方法,每种内置包装类型都有Type属性。
Class c3=Integer.TYPE;
或获得父类类型:
Class c4=c3.getSuperClass();
二,获取类的完整结构
类的完整结构包括:Field,Method,Constructor,SuperClass,Interface,Annotation
- Class c=Class.forName("com.fan.Person");
- // 获得类的名字
- System.out.println(c.getName());
- System.out.println(c.getSimpleName());
- // 获得类的属性(使用getFields的话只能访问public的属性)
- Field[] F=c.getDeclaredFields();
- for (Field f:F){
- System.out.println(f);
- }
- // 获取类的方法
- Method[] M=c.getDeclaredMethods();
- for(Method m:M){
- System.out.println(m);
- }
- // 获得指定方法,加上传参的class,因为有方法重载
- Method m=c.getDeclaredMethod("setName", String.class);
- // 获得指定的构造器
- Constructor[] c1=c.getConstructors();
三,动态创建对象并操作
- Class c=Class.forName("com.fan.Person");
- // 调用类的无参构造器构造类,类里没有无参构造器就要报错
- Person P=(Person)c.newInstance();
- // 通过有参数的构造器构造对象
- Constructor C=c.getDeclaredConstructor(int.class,String.class);
- Person P1=(Person)C.newInstance(5,"clearlove");
- // 获取函数并调用
- Method setName=c.getDeclaredMethod("setName", String.class);
- setName.invoke(P,"shy");
- System.out.println(P.getName());
- // 操作属性,通过setAccessible取消java访问权限检查
- Field name=c.getDeclaredField("name");
- name.setAccessible(true);
- name.set(P1,"the sky");
Notations:使用反射调用方法比普通方式慢很多,在反射调用前用setAccessible关闭权限会快一些。
四、获取泛型信息和注解信息
(1)获得泛型信息
- Method m=Person.class.getDeclaredMethod("test",Map.class);
- // 注意这里有很多getTypes方法,要看泛型用在了哪里就调用哪个
- Type[] generiticParameters=m.getParameterTypes();
- for (Type t:generiticParameters){
- System.out.println(t);
- // 参数是Map
,只获得了Map,需要获得真的泛型参数 - //t是一个参数化的类型,强转它获得真实的参数信息
- if(t instanceof ParameterizedType){
- Type[] actualParameterType=((ParameterizedType) t).getActualTypeArguments();
- for (Type a:actualParameterType){
- System.out.println(a);
- }
- }
(2)获取注解信息
注解定义和位置如下:
- @title("Person")
- public class Person {
- private int age;
- private String name;
-
- public Person(){
- this.age=0;
- this.name=null;
- }
-
- public Person(int age, String name) {
- this.age = age;
- this.name = name;
- }
-
- @title("test")
- public void test(Map
map) { -
- }
-
- 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;
- }
- }
-
- @Target({ElementType.METHOD,ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @interface title{
- String value();
- }
主程序中获取注解:
- //反射获得注解,这种只得到类上面的注解
- Class c=Person.class;
- Annotation[] annotations=c.getAnnotations();
- for (Annotation a:annotations){
- System.out.println(a);
- }
- // 获得注解中的值,传入注解.class可以获得注解的字节码文件
- title t;
- t = (title) c.getAnnotation(title.class);
- System.out.println(t.value());
- // 获得其他位置的注解,方法上的为例
- Method m=c.getDeclaredMethod("test",Map.class);
- System.out.println(m.getAnnotation(title.class).value());