反射的概念
当程序运行时,程序中的每一个类都会被加载到堆内存中。生成且尽每个类仅生成一个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());
}
}
}