• 78 反射——概念、类的各种信息的获取(类名,属性,方法...)


    反射的概念

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

      

  • 相关阅读:
    显示网页加载时间
    ASP.NET MVC使用jQuery来POST数据至数据库中
    jQuery的prop和attr方法之间区别
    jQuery动态产生的铵钮怎样实现事件处理
    上传Text文档并转换为PDF
    学习jQuery的on事件
    使用ViewBag传送数据从控制器至视图
    ASP.NET MVC读取XML并使用ViewData显示
    ASP.NET MVC铵钮Click后下载文件
    如何把Json格式字符写进text文件中
  • 原文地址:https://www.cnblogs.com/Scorpicat/p/12145061.html
Copyright © 2020-2023  润新知