一、反射是什么
反射机制是在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
二、反射能做什么
-
在运行时判断任意一个对象所属的类;
-
在运行时构造任意一个类的对象;
-
在运行时判断任意一个类所具有的成员变量和方法;
-
在运行时调用任意一个对象的方法;
-
生成动态代理
学习目标:
理解 Class 类
理解 Java 的类加载机制
学会使用 ClassLoader 进行类加载
理解反射的机制
掌握 Constructor、Method、Field 类的用法
理解并掌握动态代理
三、反射的API(怎么做)
1.Class类
在反射操作之前,必须理解的一个概念是Class类:
每一个类都对应有一个.class文件,.class文件被加载到内存后就对应一个运行时类,存放在缓存区。这个运行时类就是一个Class类的实例!
每一个Class类的对象都对应着一个类的类型信息!
更过详细的Class的讲解,强烈推荐:http://www.cnblogs.com/bethunebtj/p/4680532.html
2.获取Class类实例的方式
类名.class
Class clazz = Person.class;
对象.getClass()
Class clazz = person.getClass();
Class.forName("路径") 双击类名copy qualitied name获取路径
Class clazz = Class.forName("com.jiangbei.demo1.Person");
// 当然,Class是可以添加泛型的
只要类一加载,Class实例就被创建,你获取或者不获取,它就在那里,不离不弃。
3.Class类常用方法
操作的实体类如下:
package com.jiangbei.demo1.Entity; /** * 人类 * 作者: Administrator * 日期: 2017/9/19 **/ public class Human { private double weight; public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } public void eat() { System.out.println("Human#eat()..."); } }
package com.jiangbei.demo1.Entity; import java.io.Serializable; /** * 男性类 * 作者: Administrator * 日期: 2017/9/19 **/ public class Man extends Human implements Serializable{ private Integer age; private String name; public String hobby; public void show() { System.out.println("Man#show()..."); } public String play(String type) throws Exception{ System.out.println("Man#play()"+type); return "play"+type; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
创建运行时类的对象——newInstance()
@Test
public void test1() throws Exception {
String className = "com.jiangbei.demo1.Person";
// 获取Class实例
Class clazz = Class.forName(className);
// 创建运行时类的对象(通过无参公有构造器)
Person p1 = (Person) clazz.newInstance();
}
通过反射调用类的完整结构——Field、Method、Constructor、SuperClass、interface、Annotation
属性、方法、构造器、父类、接口、注解
Field
获取Field——获取单个指定的field与method,参见API
@Test public void test1() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取属性,包括父类的(只能是public的) Field[] fields1 = clazz.getFields(); for (Field field : fields1) { System.out.println(field); } // 获取属性,只能获取本身的属性(所有,只要声明了即有) Field[] fields2 = clazz.getDeclaredFields(); for (Field field : fields2) { System.out.println(field); } // 获取指定属性 Field field = clazz.getDeclaredField("age"); // System.out.println(field.getType().getName()); }
通过Field获取属性详细信息——当然还可以通过Field的set/get方法对特定对象属性进行读写操作,详见API(java.lang.reflect)
私有属性的访问问题需要先设置权限(field.setAccessible(true))
@Test public void test2() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取属性,只能获取本身的属性(所有,只要声明了即有) Field[] fields2 = clazz.getDeclaredFields(); for (Field field : fields2) { // 获取属性权限修饰符(使用Modifier进行解码) int modifiers = field.getModifiers(); System.out.println(Modifier.toString(modifiers)); // 获取属性类型(这个类型也是一个Class实例) Class type = field.getType(); System.out.println(type.getName()); // 获取属性名(简称) System.out.println(field.getName()); } }
Method
获取Method
@Test public void test3() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取方法,包括直接父类和间接父类(所有公有的方法) Method[] methods = clazz.getMethods(); /* for (Method method : methods) { System.out.println(method); }*/ // 与属性类似,获取运行时类本身的所有方法 Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } }
//列出部分方法
通过Method获取详细信息——当然还可以通过invoke()进行方法的调用,可以参见API
@Test public void test4() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 与属性类似,获取运行时类本身的所有方法 Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { // 方法注解 Annotation[] annotations = declaredMethod.getAnnotations(); // 方法修饰符 int modifiers = declaredMethod.getModifiers(); System.out.print(Modifier.toString(modifiers)); // 方法返回值 Class returnType = declaredMethod.getReturnType(); System.out.println(returnType.getName()); // 方法名 String name = declaredMethod.getName(); System.out.print(name); // 形参列表(一般关心类型,形参名字不是重点) Class[] paraTypes = declaredMethod.getParameterTypes(); // 抛出异常 Class[] exceptionTypes = declaredMethod.getExceptionTypes(); System.out.println(); } }
Constructor
获取构造器——可以通过构造器的newInstance()来进行对象的构造
@Test public void test5() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取构造器,本身公有的构造器 Constructor[] constructors = clazz.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor.getName()); } }
Supperclass
获取运行时父类(获取父类的泛型)
@Test public void test6() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取父类 Class superclass = clazz.getSuperclass(); System.out.println(superclass.getSimpleName()); // 获取父类的泛型 Type genericSuperclass = clazz.getGenericSuperclass(); ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); System.out.println(((Class)actualTypeArguments[0]).getName()); }
Interfaces
获取实现的所有接口
@Test public void test7() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取接口 Class[] interfaces = clazz.getInterfaces(); for (Class anInterface : interfaces) { System.out.println(anInterface.getName()); } }
Package
获取包
@Test public void test7() throws Exception { String className = "com.jiangbei.demo1.Entity.Man"; // 获取Class实例 Class clazz = Class.forName(className); // 获取包 Package aPackage = clazz.getPackage(); System.out.println(aPackage.getName()); }
其它的获取内部类、类注解的不再赘述
更多反射相关,参考:这里