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<String,Integer>,只获得了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<String,Integer> 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());