反射

反射

什么是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 关键字创建对象.减少开发量。

原文地址:https://www.cnblogs.com/lyang-a/p/12558001.html