zoukankan      html  css  js  c++  java
  • 反射

    反射

    什么是Java反射?

      反射是一种机制,通过某种找到其源信息.在Java中,反射是一种动态加载类运行的机制。在Java中,类包含:

      属性/构造方法/方法/注解。由于一个类由以上信息组成,那么Java的反射机制,本质上就是要找到正在运行或者编译的类信息中的属性/构造方法/方法/注解。

    如何使用反射?

     Java中反射机制的由来

      在Java中,任何类都可以包含:属性/构造方法/方法/注解。

        1. 所有的属性封装一个类: Field 属性名 属性类型

        2. 所有的构造方法封装一个类: Constructor 方法名 方法参数

        3. 所有的方法封装一个类:Method 返回值类型 方法名称 参数列表

        4. 所有的注解都封装成一个类: Annotation 注解类型 属性名称 值

        5. 将所有的类封装成一个类: Class 属性 Field 构造方法Constructor 方法 Method 注解 Annotation

    如何使用反射

    获取类对应的Class类对象

      为此Java提供了三种方式获取类对应的Class对象:

    Class cls = 类名.class
    Class cls = 类对象.getClass()
    Class cls = Class.forName("类的全路径")  
    

     第三种方式最实用,因为类的全路径是字符串.字符串具有通用性.其他语言也有字符串,各种配置文件本质上也都是字符串.

    通过Class类对象,调用方法,获取其属性、方法、构造函数、注解

      1. 属性:Field

     Field 	     getDeclaredField(String name)	// 根据属性名获取对应的属性(包含私有的 private )
     Field       getField(String name)	//根据属性名获取公共的属性(只有共有的  public 修饰的)
     Field[]     getDeclaredFields()	// 返回类中所有的属性(包含私有的)
     Field[]     getFields() 	//返回类中所有public 修饰的属性
    

    注意:getDeclaredFields() 只会获取类自身所有属性,不会获取从父类继承的属性.getFields()获取所有公共属性,包括继承的属性.

      2. 方法:Method

     //由于方法存在方法的重载,即方法名称可以相同,所以查找方法时,需要带上参数进行区分 
     // 根据方法名称,参数列表类型获取方法
     Method     getDeclaredMethod(String name, Class<?>... parameterTypes) 
     //根据方法名称,参数列表类型获取public 修饰的方法     
     Method     getMethod(String name, Class<?>... parameterTypes)
     //获取自身的所有方法    
     Method[]   getDeclaredMethods()
     //获取父类的方法及自身的所有public 修饰的方法    
     Method[]   getMethods() 
    

    注意:getDeclaredMethods()只会获取类自身的所有方法,不会获取从父类集成的方法.getMethods() 获取所有公共的方法,包括继承.

      3. 构造函数:Constructor

     // 根据参数列表获取自身公共的构造方法
     Constructor<T>		getConstructor(Class<?>... parameterTypes) 
     // 根据参数列表获取自身构造方法
     Constructor<T>		getDeclaredConstructor(Class<?>... parameterTypes) 
     // 获取自身所有的公共的构造方法    
     Constructor<?>[]	getConstructors() 
     // 获取自身所有的构造方法    
     Constructor<?>[]	getDeclaredConstructors() 
    

    什么是注解

        注释,备注,解释.注释目标 .

       目标: 类,属性,构造器,方法,参数,注解.

       有效期:

        基于注解,2个核心: 目标,有效期. Java提供元注解:

        @Retention、@Documented、@Target、@Inherited、@Repeatable

       核心:

      @Retention 英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

      1. RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视
      2. RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中
      3. RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们

      @Target 是目标的意思,@Target 指定了注解运用的地方。

        1. ElementType.ANNOTATION_TYPE  可以给一个注解进行注解
        2. ElementType.CONSTRUCTOR  可以给构造方法进行注解
        3. ElementType.FIELD  可以给属性进行注解
        4. ElementType.LOCAL_VARIABLE  可以给局部变量进行注解
        5. ElementType.METHOD  可以给方法进行注解
        6. ElementType.PACKAGE  可以给一个包进行注解
        7. ElementType.PARAMETER  可以给一个方法内的参数进行注解
        8. ElementType.TYPE  可以给一个类型进行注解,比如类、接口、枚举

      如何定义注解?

        注解只有属性,且定义的方式类似于抽象无参方法.方法名就是属性名,返回值类型就是属性类型

       语法:

       在java中,创建一个注解:

    public @interface 注解名称{
    	Integer annotationName();
    }
    
    package com.sxt.annotation.demo01;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 注解示例     目标    有效期
     * @author mrt
     */
    // 作用目标
    @Target(value= {ElementType.ANNOTATION_TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
    // 有效期
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AnnotationDemo01 {
    	//  int  注解属性的类型   value 属性的名称
    	int value();
    	// int 注解属性类型   id 属性的名称  default 0 属性的默认值
    	int  id() default 0;
    }
    

    反射中获取注解:

    // 根据注解的类型,获取该注解
    <A extends Annotation> A	getAnnotation(Class<A> annotationClass) 
    // 获取对象(类对象   属性对象   方法对象   构造方法对象  注解对象)所有的注解
    Annotation[]    			getDeclaredAnnotations() 
    
    package com.sxt.annotation.demo01;
    
    import java.lang.annotation.Annotation;
    
    public class Test {
    	
    	public static void main(String[] args) {
    		// 获取类对应的Class  类对象
    		Class cls = AnnotationTest.class;
    		//根据注解类型  获取 对应注解
    		AnnotationDemo01 annotation = (AnnotationDemo01) cls.getAnnotation(AnnotationDemo01.class);
    		System.out.println(annotation);
    		// 访问注解中的属性
    		System.out.println(annotation.id() +"   "+annotation.value());
    		// 获取对象上直接的所有注解
    		Annotation[] annotations = cls.getDeclaredAnnotations();
    		for (Annotation annotation2 : annotations) {
    			System.out.println(annotation2);
    		}
    	}
    
    }
    

    Field类

    ​ Field属性,在Java中指的是类的成员变量.访问修饰符 属性类型 属性名称

    成员变量是对象

      // 获取属性(成员变量)的值,obj 指定的成员变量所属的对象
      Object		get(Object obj) 
      // 获取属性上指定的注解
      <T extends Annotation> T		getAnnotation(Class<T> annotationClass) 
       //获取属性上所有的注解   
      Annotation[]    	getDeclaredAnnotations() 
      // 获取属性名称    
      String     	getName() 
      // 获取属性类型     
      Class<?>    	getType()
      // 为属性赋值  Object obj  所属对象, Object value  值   
      void    		set(Object obj, Object value) 
      // 获取访问修饰符    
      int getModifiers()
    
    package com.sxt.reflect.demo02;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    
    import com.sxt.annotation.demo01.AnnotationDemo01;
    
    /**
     * 演示 Field类中方法
     * @author mrt
     *
     */
    public class FieldTest {
    	
    	@AnnotationDemo01(10)
    	private Integer id;
    	
    	private String name;
    	
    
    	
    	public static void main(String[] args) throws Exception {
    		//1. 类对应的Class 对象
    		Class cls = FieldTest.class;
    		// 找到类中属性
    		Field id = cls.getDeclaredField("id");
    		Field name = cls.getDeclaredField("name");
    		//获取属性名称
    		System.out.println(id.getName());
    		//获取属性的类型
    		System.out.println(id.getType().getSimpleName());
    		//获取属性上的注解
    		AnnotationDemo01 annotation = id.getAnnotation(AnnotationDemo01.class);
    		System.out.println(annotation.value());
    		//获取属性上所有的注解
    		Annotation[] annotations = id.getDeclaredAnnotations();
    		for (Annotation annotation2 : annotations) {
    			System.out.println(annotation2);
    		}
    		// 获取属性值
    		FieldTest obj1 = new FieldTest();
    		obj1.id = 100;
    		obj1.name = "韩梅梅";
    		FieldTest obj2 = new FieldTest();
    		obj2.id = 101;
    		obj2.name = "李磊";
    		Object object1 = id.get(obj1);
    		System.out.println(object1);
    		
    		Object object2 = id.get(obj2);
    		System.out.println(object2);
    		//设置属性值
    		FieldTest obj3 = new FieldTest();
    		id.set(obj3, 102);
    		name.set(obj3, "Lucy");
    		System.out.println(obj3.id+"   "+ obj3.name);
    	}
    }
    
    

    Mthod

    Method在java中,表示的方法.注解 访问修饰符 返回值 方法名称 参数列表 [声明的异常]

    // 获取方法上指定的注解
    <T extends Annotation> T	getAnnotation(Class<T> annotationClass) 
     //获取方法上所有的注解
     Annotation[]    			getDeclaredAnnotations() 
     // 获取方法名称
     String    		getName() 
     // 获取访问修饰符
     int    		getModifiers() 
     // 获取参数类型列表   
     Class<?>[]		getParameterTypes() 
     // 获取返回值类型   
     Class<?>    	getReturnType() 
     // 执行方法      Object obj 执行该方法的对象  , Object... args   参数
     invoke(Object obj, Object... args) 
    
    package com.sxt.reflect.demo02;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Method;
    
    import com.sxt.annotation.demo01.AnnotationDemo01;
    
    /**
     * Method 类中 核心 方法
     * @author mrt
     *
     */
    public class MethodTest {
    	
    	@AnnotationDemo01(1)
    	public void test1() {
    		System.out.println(" 我是共有的的 无参  无返回值的  方法  test1  ");
    	}
    	
    	public static void main(String[] args) throws Exception {
    		//1.找到类对应Class 类对象
    		Class cls = MethodTest.class;
    		// 根据名称 和参数找到对应的方法
    		Method m  = cls.getDeclaredMethod("test1");
    		// 获取方法名称
    		System.out.println(m.getName());
    		// 获取返回值类型
    		System.out.println(m.getReturnType());
    		// 参数个数
    		System.out.println(m.getParameterCount());
    		// 参数类型列表
    		System.out.println(m.getParameterTypes().length);
    		//获取方法上的注解
    		AnnotationDemo01 annotation = m.getDeclaredAnnotation(AnnotationDemo01.class);
    		System.out.println(annotation);
    		//获取所有注解
    		Annotation[] annotations = m.getDeclaredAnnotations();
    		for (Annotation annotation2 : annotations) {
    			System.out.println(annotation2);
    		}
    	}
    
    }
    
    

    公共方法:

    // 设置访问权限   当私有时,在其他类中,使用反射去访问属性或者方法需要设置访问权限 设置为  true
    setAccessible(boolean b) 
    //使用反射创建对象    
    newInstance() 
    

    反射案例

    在实际生产场景,要经常做数据的校验.在A处要进行数据校验,在B处也要进行数据校验.

    数据校验工具类:

    package com.sxt.reflect.demo03;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 指定字符串长度
     * @author mrt
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Length {
    	
    	/**
    	 * 	最小长度
    	 * @return
    	 */
    	int min() default  1;
    	/**
    	 * 	最大长度
    	 * @return
    	 */
    	int max() default  10;
    	/**
    	 * 	不符合时的提示信息
    	 * @return
    	 */
    	String message() default "";
    
    }
    
    
    package com.sxt.reflect.demo03;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 校验整数
     * @author mrt
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Range {
    	/**
    	 * 	最小数值
    	 * @return
    	 */
    	int min() default  1;
    	/**
    	 * 	最大数值
    	 * @return
    	 */
    	int max() default  Integer.MAX_VALUE;
    	/**
    	 * 	不符合时的提示信息
    	 * @return
    	 */
    	String message() default "";
    }
    
    package com.sxt.reflect.demo03;
    
    public class UserForm {
    	
    	@Length(min = 7,max=20,message = "用户名字只能为6-20位"  )
    	private String name;
    	
    	@Length(max=50,message = "用户地址最多50字符"  )
    	private String address;
    	
    	@Range(min=15,max=25,message = "年龄的范围只能为15-25")
    	private int age;
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getAddress() {
    		return address;
    	}
    
    	public void setAddress(String address) {
    		this.address = address;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    	
    }
    
    package com.sxt.reflect.demo03;
    
    import java.lang.reflect.Field;
    
    /**
     * 数据校验工具类
     */
    public class ValidatorUtil {
    
    	/**
    	 * 校验对象的属性是否符合要求
    	 * @param obj  需要被校验的对象
    	 * @return
    	 */
    	public static String validator(Object obj) {
    		// 获取需要被校验的对象的Class 类对象
    		Class cls = obj.getClass();
    		// 获取所有的属性
    		Field[] fields = cls.getDeclaredFields();
    		//校验所有属性的字符串长度
    		for (Field field : fields) {
    			//获取属性上 length注解
    			Length length = field.getAnnotation(Length.class);
    			if(length != null) {
    				int min = length.min();// 最小长度限制
    				int max = length.max();// 最大长度限制
    				try {
    					//获取属性值
    					field.setAccessible(true);
    					Object o = field.get(obj);
    					//获取属性值 字符串长度
    					int len = o.toString().length();
    					//假如 属性的值 不符合要求 则返回提示信息
    					if(len < min || len > max ) {
    						//返回提示信息
    						return length.message();
    					}
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    			//校验数字的大小
    			Range range = field.getAnnotation(Range.class);
    			if(range != null) {
    				int min = range.min();// 最小长度限制
    				int max = range.max();// 最大长度限制
    				try {
    					//获取属性值
    					field.setAccessible(true);
    					Object o = field.get(obj);
    					//获取属性值 字符串长度
    					int len = o.toString().length();
    					//假如 属性的值 不符合要求 则返回提示信息
    					if(len < min || len > max ) {
    						//返回提示信息
    						return range.message();
    					}
    				} catch (Exception e) {
    					e.printStackTrace();
    				}
    			}
    			
    		}
    		return null;
    	}
    }
    
    
    package com.sxt.reflect.demo03;
    
    public class Test {
    	
    	public static void main(String[] args) {
    		
    		UserForm  form = new UserForm();
    		form.setName("韩梅梅你好啊啊");
    		form.setAddress("一二三四五一二三四五一");
    		form.setAge(100);
    		String rs = ValidatorUtil.validator(form);
    		if(rs != null) {
    			System.out.println(rs);
    		}
    	}
    
    }
    

    Map工具类

    将Map 转化为Java对象或者将Java对象转化为Map

    package com.sxt.reflect.demo04;
    
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    /**
     *  Map 工具类   
     */
    public class MapUtil {
    		
    	/**
    	 * 将Map转化为JavaBean对象
    	 * map 数据  由 key-value组成, key的值与类的属性值 相同,key对应的值,恰好是属性的值
    	 * 根据map的key的值,获取类的该属性,然后为这个属性赋值
    	 * @param <T>
    	 * @return
    	 */
    	public static <T> T mapToBean(Map<String,Object> data,Class<T> cls) {
    		T t = null;
    		try {
    			t = cls.newInstance();
    			//获取所有属性
    			Field[] fields = cls.getDeclaredFields();
    			//遍历属性
    			for (Field field : fields) {
    				//获取属性名
    				String name = field.getName();
    				//判断Map中是否存在指定key
    				if(data.containsKey(name)) {
    					//获取key 对应的值
    					Object o = data.get(name);
    					field.setAccessible(true);
    					field.set(t, o);
    				}
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} 
    		//
    		return t;
    	}
    	
    	/**
    	 * 将JavaBean 转化为Map
    	 * 将JavaBean中属性作为Map的key  值作为key对应的值
    	 * @param obj
    	 * @return
    	 */
    	@SuppressWarnings("rawtypes")
    	public static Map<String, Object> beanToMap(Object obj) {
    		Class cls = obj.getClass();
    		// 获取所有属性
    		Field[] fields = cls.getDeclaredFields();
    		Map<String, Object> data = new HashMap<String, Object>();
    		for (Field field : fields) {
    			String key = field.getName();
    			field.setAccessible(true);
    			try {
    				Object value = field.get(obj);
    				data.put(key, value);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		return data;
    	}
    	
    	public static void main(String[] args) {
    		Map<String,Object> data = new HashMap<String,Object>();
    		data.put("id", 101);
    		data.put("name", "韩梅梅");
    		data.put("sex", "女");
    		data.put("age", 18);
    		data.put("phone", "13111111111");
    		
    		User user = MapUtil.mapToBean(data, User.class);
    		System.out.println(user);
    		
    		Map<String, Object> beanToMap = MapUtil.beanToMap(user);
    		System.out.println(beanToMap);
    	}
    
    }
    

    JDBC

    jdbc的操作步骤:

    1. 加载驱动

    2. 创建连接

    3. 获取数据库操作对象

    4. 定义SQL

    5. 执行sql

    6. 处理结果

    7. 释放资源

    反射的意义?

    在Java中,反射可以动态调用执行类中相关信息.可以大大提高代码的复用性.但是反射的性能远远低于直接使用 new 关键字创建对象.减少开发量。

  • 相关阅读:
    连接数据库的几种方式
    c#拖拽文件
    设置webbrowser浏览器内核
    C#控件置于底层或顶层
    C#中读取xml文件指定节点
    关于selenium python Message: unknown error: Element is not clickable at point错误
    Linux的命令操作
    MySQL数据库的知识
    没有添加main方法
    eclipse导入已建工程
  • 原文地址:https://www.cnblogs.com/lyang-a/p/12558001.html
Copyright © 2011-2022 走看看