反射
什么是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的操作步骤:
-
加载驱动
-
创建连接
-
获取数据库操作对象
-
定义SQL
-
执行sql
-
处理结果
-
释放资源
反射的意义?
在Java中,反射可以动态调用执行类中相关信息.可以大大提高代码的复用性.但是反射的性能远远低于直接使用 new 关键字创建对象.减少开发量。