反射的机制
1.JAVA是静态语言不是动态语言,但是可以通过反射让JAVA具有一定的动态性(准动态)
2.程序在运行状态中可以动态的加载一个只有名称的类,对于一个任意的已经加载的类,我们能够知道这个类的所有方法和属性;对于任意一个对象都能够调用它任意的方法。通俗来说,通过反射我们可以知道任意一个类的方法和属性且能够调用它的方法,而不用静态的new一个对象出来
Class clazz = Class.forName("com.jyg.bean.Student");
类加载之后形成一个Class对象放在堆内存中,Class对象包含了完整的类信息。那么我们通过Class对象来看到类的结构,就像一面镜子
注意:一个Class创建出来的对象只有一份。
放射的作用
- 动态加载类、动态获取类信息(属性、方法、构造器)
- 动态构造对象
获取类名字
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
//获得类路径
String className = clazz.getName();
//获得类名
String classSimpleName = clazz.getSimpleName();
System.out.println(className+"--"+classSimpleName);
获得类属性
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
//获得公开的属性
Field[] fields = clazz.getFields();
Field field = clazz.getField("pu_name");
//获得所有属性
Field[] declaredFields = clazz.getDeclaredFields();
Field declaredField = clazz.getDeclaredField("name");
System.out.println(Arrays.asList(declaredFields));
System.out.println(declaredField);
获取类方法
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
//获得类方法,公开的方法
Method[] methods = clazz.getMethods();
Method goHome = clazz.getMethod("goHome");
//获得类方法,所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
//参数列表:方法名,方法参数类型(用来区别同名方法)
clazz.getMethod("goHome",null);
获取类构造器
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
//获得类构造器,相当于调用无参构造器
//注意Bean规定一定要实现无参构造器,
Student student = (Student) clazz.newInstance();
//通过参数类型来确定要用哪一个构造器(区别同名构造器)
Constructor constructor = clazz.getConstructor(String.class, int.class);
Student student1 = (Student) constructor.newInstance("JYG",18);
- 动态调用类和对象的任意方法。构造器
调用方法
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
Student student = (Student) clazz.newInstance();
Method doHomeWork = clazz.getMethod("doHomeWork", String.class, String.class);
//获得返回值类型
Class<?> returnType = doHomeWork.getReturnType();
//获得参数列表类型
Class<?>[] parameterTypes = doHomeWork.getParameterTypes();
//获得.....
//调用方法
Object methodReturn = doHomeWork.invoke(student,"JYG","数学作业");
System.out.println(methodReturn);
- 动态调用和处理属性
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
Student student = (Student) clazz.newInstance();
Field name = clazz.getDeclaredField("name");
name.set(student,"JYG");
System.out.println(student.getName());
此处会报错(IllegalAccessException)因为虚拟机对属性的访问做了安全检查,name属性是私有不能被外部访问。但是可以手动关闭安全检查来达到操作属性的目的
String classPath = "com.jyg.bean.Student";
Class clazz = Class.forName(classPath);
Student student = (Student) clazz.newInstance();
Field name = clazz.getDeclaredField("name");
//关闭安全检查
name.setAccessible(true);
name.set(student,"JYG");
System.out.println(student.getName());
setAccessible也涉及到一个性能问题,关闭检查能比打开检查的执行效率提高约4倍左右。当我们确定要用反射且频繁调用时可以禁用安全检查
-
获取泛型
篇幅原因,可自行百度 -
处理注解
Class clazz = Class.forName("com.jyg.bean.Student");
Field[] fields = clazz.getFields();
//拿到类的注解
TableName tableName = (TableName) clazz.getAnnotation(TableName.class);
//拿到name属性的注解
Field f = clazz.getDeclaredField("name");
FieldName fieldName = f.getAnnotation(FieldName.class);
System.out.println(tableName.value());
System.out.println(fieldName.coumlnName()+"--"+fieldName.type()+"--"+fieldName.length());
@TableName(value = "pro_student")
public class Student {
@FieldName(coumlnName = "stu_name",type = "varchar" ,length = 20)
private String name;
@FieldName(coumlnName = "stu_age",type = "int" ,length = 3)
private int age;
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TableName {
String value();
}
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface FieldName {
String coumlnName();
String type();
int length();
}