反射的概念
当程序运行时,程序中的每一个类都会被加载到堆内存中。生成且尽每个类仅生成一个Class对象。这个对象保存了整个类的结构信息,包括这个类的所有属性与方法甚至注解。就像一面镜子一样。所以我们称之为反射。
当我们说反射时,说的就是Class类与java.lang.reflect包中的类
每个类对应一个Class对象
java.lang.Class类保存了每一类的唯一一个对象。如下,当我们使用Class.forName()创建两个Class引用时,它们指向同一个对象。
每一个类包括基础数据类型的八大类及String、各基础数据类型对应的数组,枚举、接口、甚至Annotation注解。
public class Test { public static void main(String[] args) throws ClassNotFoundException { String path = "_20200103_reflection.Test"; Class c1 = Class.forName(path); Class c2 = Class.forName(path); System.out.println(c1.hashCode()); System.out.println(c2.hashCode()); } } //运行结果 705927765
705927765
获取Class对象的三种方式
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException { String path = "_20200103_reflection.User"; User u = new User(); //获取Class对象的三种方式: //1.Class.forName(包名.类名) Class<?> c1 = Class.forName(path); //2.已知类,直接:类.class Class<?> c2 = _20200103_reflection.User.class; //3.已知实例。实例.getClass() Class<?> c3 = u.getClass(); System.out.println(c1); System.out.println(c2); System.out.println(c3); } }
//运行结果
class _20200103_reflection.User
class _20200103_reflection.User
class _20200103_reflection.User
反射的常用方法
以下代码完整代码将在文末贴出。
一个Class对象包含了一个类的结构信息,包括:类名、参数、属性、方法、构造器、注解等等。我们来一一获取它们。
以下运行结果可能与最终代码运行结果有不同,因为我是边写此文边写代码的。
获取类名
String path = "_20200104_review.User";
//反射获得Class对象
Class<?> clz = Class.forName(path);
//获取类名
System.out.println("类名:"+clz.getName());
获取构造方法
- getConstructors()获取public修饰的构造器数组
- getDeclaredConstructors()获取所有的构造器数组
//获取构造方法
//获取无参构造
Constructor<?> cons1 = clz.getConstructor(null);
//获取有参构造
Constructor<?> cons2 = clz.getConstructor(int.class,String.class,String.class);
获取实例
Object user1 = cons2.newInstance(18,"1002","小明");
获取方法
- getMethods获取包括继承来的所有public方法
- getDeclaredMethods获取所有该类声明的方法,包括private修饰的
- 获取指定的方法 getMethod(String methodName,Class parameterClass) ,按指定参数获取方法,参数为:方法名,参数对应的Class对象,如String.class , int.class等等
System.out.println("----获取方法-------"); //获取所有的public方法,包括继承来的 Method[] methods = clz.getMethods(); System.out.println(methods.length); //获取所有的声明的方法:包括私有方法,不包括继承来和构造方法 Method[] methods1 = clz.getDeclaredMethods(); System.out.println(methods1.length); //获取指定的方法:getId方法 Method method = clz.getDeclaredMethod("getId",null); Method method1 = clz.getDeclaredMethod("test02", int.class); Method method2 = clz.getDeclaredMethod("test01", Map.class);
获取属性
System.out.println("----获取属性-------"); //获取所有public修饰的属性,不包括继承来的 Field[] fields = clz.getFields(); System.out.println(fields.length); //获取所有声明的属性,包括私有的 Field[] fields2 = clz.getDeclaredFields(); System.out.println(fields2.length); //获取指定声明的属性 Field field = clz.getDeclaredField("name"); System.out.println(field); //获取指定的公开的属性 Field field2 = clz.getField("id"); System.out.println(field2);
获取属性值
注意:如果使用 反射属性.get(反射实例) 的方式获取属性值,需要在前面写一句:反射属性.setAccessible(true)
同样地,当使用反射直接调用一个private修饰的方法时,也需要写:反射方法.setAccessible(true);
//读取属性值 //方法一:通过反射属性.get(反射Class对象) field2.setAccessible(true); System.out.println(field2.get(user1)); //方法二:通过反射实例向下转型调用类中的getId方法 System.out.println(((User)user1).getId());
读取方法的参数类型
//读取参数类型 System.out.println("----获取参数类型----"); Class<?>[] parameters = method1.getParameterTypes(); for(Class p : parameters) { System.out.println("参数:"+p); }
读取方法的返回值类型
//读取返回值类型 Class<?> returnType = method.getReturnType(); System.out.println(returnType);
读取方法的泛型参数类型与泛型参数的实参的类型
//获取方法的泛型参数类型 Type[] genericTypes = method2.getGenericParameterTypes(); for(Type parameter : genericTypes) { System.out.println("泛型参数:"+parameter); //获取方法的泛型参数的实参类型 if(parameter instanceof ParameterizedType) { Type[] argumentsType = ((ParameterizedType)parameter).getActualTypeArguments();//parameter表示形参,argument表示实参 for(Type argumentType : argumentsType) { System.out.println("泛型的实参类型为:"+argumentType); } } }
读取方法的泛型返回值类型的实参的类型
//读取泛型返回值类型 Type returnGenericType = method2.getGenericReturnType(); System.out.println(returnGenericType); //读取泛型返回值类型之实参类型 if(returnGenericType instanceof ParameterizedType){ Type[] actualtp = ((ParameterizedType) returnGenericType).getActualTypeArguments(); for(Type acp : actualtp) { System.out.println("返回值泛型参数的实参类型:"+acp); } }
获取注解
思路:
- 反射获取Class对象
- Class对象调用getAnnotations获取注解数组
- 或调用GetAnnottation(具体注解的Class对象)
System.out.println("---获取类注解---"); Annotation[] annos = clz.getAnnotations(); for(Annotation a : annos) { System.out.println("类注解的值为:"+a); } System.out.println("----获取属性注解----"); for(Field f : fields2) { UserField a= f.getAnnotation(UserField.class); System.out.println("columnName:"+a.columnName()+" tpe:"+a.type()+" length:"+a.length()); }
扩展内容
ParameterizedType是最常用的关于泛型的一个类,其他还有不常用的如下:
运行结果
类名:_20200104_review.User ----获取方法------- 17 9 ----获取属性------- 1 3 private java.lang.String _20200104_review.User.name public java.lang.String _20200104_review.User.id 1002 1002 ----获取参数类型---- 参数:int ----获取返回值类型----- class java.lang.String ----获取泛型参数及参数的实参类型---- 泛型参数:java.util.Map<java.lang.String, java.lang.Integer> 泛型的实参类型为:class java.lang.String 泛型的实参类型为:class java.lang.Integer ----读取泛型返回值类型---- java.util.List<java.lang.String> 返回值泛型参数的实参类型:class java.lang.String ---获取类注解--- 类注解的值为:@_20200104_review.UserTable(value=user_table) ----获取属性注解---- columnName:age tpe:varchar length:5 columnName:id tpe:int length:10 columnName:name tpe:carchar length:10
完整代码
User类
package _20200104_review; import java.util.ArrayList; import java.util.List; import java.util.Map; @UserTable("user_table") public class User extends Person{ @UserField(columnName="age",type="varchar",length=5) private int age; @UserField(columnName="id",type="int",length=10) public String id; @UserField(columnName="name",type="carchar",length=10) private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User(int age, String id, String name) { super(); this.age = age; this.id = id; this.name = name; } public User() { super(); } private List<String> test01(Map<String,Integer> map) { System.out.println("我是私有方法test01"); return null; } public void test02(int num) { System.out.println("我是公有方法test"+num); } public static void main(String[] args) { User u = new User(); } }
注解类:UserTable
package _20200104_review; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface UserTable { String value(); }
注解类:UserField
package _20200104_review; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface UserField { String columnName(); String type(); int length(); }
测试类
package _20200104_review; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Map; /** * 读取User类的信息 * @author TEDU * */ public class ReflectionTest { public static void main(String[] args) throws Exception{ String path = "_20200104_review.User"; //反射活得Class对象 Class<?> clz = Class.forName(path); //获取类名 System.out.println("类名:"+clz.getName()); //获取构造方法 //获取无参构造 Constructor<?> cons1 = clz.getConstructor(null); //获取有参构造 Constructor<?> cons2 = clz.getConstructor(int.class,String.class,String.class); //获取实例 Object user1 = cons2.newInstance(18,"1002","小明"); //读取方法 System.out.println("----获取方法-------"); //获取所有的public方法,包括继承来的 Method[] methods = clz.getMethods(); System.out.println(methods.length); //获取所有的声明的方法:包括私有方法,不包括继承来和构造方法 Method[] methods1 = clz.getDeclaredMethods(); System.out.println(methods1.length); //获取指定的方法:getId方法 Method method = clz.getDeclaredMethod("getId",null); Method method1 = clz.getDeclaredMethod("test02", int.class); Method method2 = clz.getDeclaredMethod("test01", Map.class); //读取属性 System.out.println("----获取属性-------"); //获取所有public修饰的属性,不包括继承来的 Field[] fields = clz.getFields(); System.out.println(fields.length); //获取所有声明的属性,包括私有的 Field[] fields2 = clz.getDeclaredFields(); System.out.println(fields2.length); //获取指定声明的属性 Field field = clz.getDeclaredField("name"); System.out.println(field); //获取指定的公开的属性 Field field2 = clz.getField("id"); System.out.println(field2); //读取属性值 //方法一:通过反射属性.get(反射Class对象) field2.setAccessible(true); System.out.println(field2.get(user1)); //方法二:通过反射实例向下转型调用类中的getId方法 System.out.println(((User)user1).getId()); //读取参数类型 System.out.println("----获取参数类型----"); Class<?>[] parameters = method1.getParameterTypes(); for(Class p : parameters) { System.out.println("参数:"+p); } System.out.println("----获取返回值类型-----"); //读取返回值类型 Class<?> returnType = method.getReturnType(); System.out.println(returnType); //读取泛型参数及其实参类型 System.out.println("----获取泛型参数及参数的实参类型----"); //获取方法的泛型参数类型 Type[] genericTypes = method2.getGenericParameterTypes(); for(Type parameter : genericTypes) { System.out.println("泛型参数:"+parameter); //获取方法的泛型参数的实参类型 if(parameter instanceof ParameterizedType) { Type[] argumentsType = ((ParameterizedType)parameter).getActualTypeArguments();//parameter表示形参,argument表示实参 for(Type argumentType : argumentsType) { System.out.println("泛型的实参类型为:"+argumentType); } } } //读取泛型返回值类型 System.out.println("----读取泛型返回值类型----"); //读取泛型返回值类型 Type returnGenericType = method2.getGenericReturnType(); System.out.println(returnGenericType); //读取泛型返回值类型之实参类型 if(returnGenericType instanceof ParameterizedType){ Type[] actualtp = ((ParameterizedType) returnGenericType).getActualTypeArguments(); for(Type acp : actualtp) { System.out.println("返回值泛型参数的实参类型:"+acp); } } //读取注解 System.out.println("---获取类注解---"); Annotation[] annos = clz.getAnnotations(); for(Annotation a : annos) { System.out.println("类注解的值为:"+a); } System.out.println("----获取属性注解----"); for(Field f : fields2) { UserField a= f.getAnnotation(UserField.class); System.out.println("columnName:"+a.columnName()+" tpe:"+a.type()+" length:"+a.length()); } } }