第一章 反射的概述
第1节 反射的概念
Java的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java的反射机制. |
第2节 反射理解
1 | 如果存在反射,那是不是也存在正射?如果存在正射,那么什么是正射呢? |
- 白话正射
1 2 3 4 | 在编写代码的时,如果使用到了某一个类,首先需要了解这个类是干什么的,然后使用new关键字实例化对象.接着对这个对象进行操作,这就是正射. Teacher t = new Teacher();//实例化 t.doWork("语文");//调用方法(操作对象) |
- 白话反射
1 | 反射就是我们不知道要创建对象的类是什么,自然也就无法使用new关键字来创建对象,但是我还想创建对象 |
- 正射和反射的对比
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* * 下面是使用正射和反射实现的 * 功能相同 */ public class TestDemo02 { public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException { //正射 Teacher t = new Teacher(); t.doWork("语文"); //反射 Teacher obj = (Teacher) createObject("cn.ukoko.Teacher"); obj.doWork("数学"); } public static Object createObject(String o) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class<?> c = Class.forName(o); Object obj = c.newInstance(); return obj; } } class Teacher{ void doWork(String w){ System.out.println("老师批改"+w+"作业..."); } } |
第二章 反射常见API
1 2 3 4 | java.lang.Class: 描述类的类 java.lang.reflect.Method: 描述方法的类 java.lang.reflect.Field: 描述属性的类 java.lang.reflect.Constructor: 描述构造器的类 |
第1节 Class类
1 2 3 4 5 6 7 | Class被称为描述类的类,他也是一个类,从这个类中可以获取一个类的描述信息,比如获取类中属性的信息,方法的信息,构造器的信息等. 1. Class类没有构造方法,他的对象只能由系统创建,不能由程序员创建. 2. 一个类在 JVM 中只会有一个Class实例 3. 一个Class对象对应的是一个加载到JVM中的一个.class文件 4. 每个类的实例都会记得自己是由哪个 Class 实例所生成 5. 通过Class可以完整地得到一个类中的完整结构 |
- Class类的常见方法
方法名 | 功能说明 |
---|---|
static Class forName(String name) | 返回指定类名 name 的 Class 对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
Class [] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Constructor[] getConstructors() | 返回所有public修饰的构造方法 |
Constructor[] getDeclaredConstructors() | 返回所有权限修饰的构造方法 |
Field[] getFields() | 返回所有的public修饰的属性,包含父类 |
Field[] getDeclaredFields() | 返回当前类的所有权限的属性(不包括父类) |
Method[] getMethods() | 返回所有的public修饰的方法(包括父类) |
Method[] getDeclaredMethods | 返回当前类的所有权限的方法(不包括父类) |
Annotation[] getAnnotations() | 返回所有注解(包括父类的注解,父类注解使用@Inherited修饰) |
Annotation[] getDeclaredAnnotations() | 返回当前类的注解 |
Type getGenericSuperclass() | 获取父类的泛型类型 |
ParameterizedType | ParameterizedType是Type的子类getGenericSuperclass()方法返回的对象是ParameterizedType的实例,所以需要造型(向上强转) |
Type[] getActualTypeArguments() | ParameterizedType中提供了getActualTypeArguments方法,返回泛型类型列表 |
- 获取Class类对象的常见3种方式
1 2 3 4 5 6 7 8 9 10 11 12 | 1. 使用 Class.forName 静态方法 Class<?> clazz = Class.forName("java.lang.String"); System.out.println(clazz);//class java.lang.String 2. 使用类的.class 方法 Class<String> clazz = String.class; System.out.println(clazz);//class java.lang.String 3. 使用实例对象的 getClass() 方法 String s = new String("xxx"); Class<? extends String> clazz = s.getClass(); System.out.println(clazz);//class java.lang.String |
第2节 Method类
1 | 描述方法的方法 |
- Method类的常见方法
方法名 | 功能说明 |
---|---|
int getModifiers() | 权限修饰符 |
String getName() | 方法名 |
Class<?>[] getParameterTypes() | 方法的参数列表类型 |
Class<?>[] getReturnType() | 返回值类型 |
Object invoke(Object obj, Object… args) | 方法调用 |
第3节 Field类
1 | 描述属性的类 |
- Field类的常见方法
方法名 | 功能说明 |
---|---|
Object get(Object obj) | 获取指定属性值 |
int getModifiers() | 获取属性的权限修饰符 |
String getName() | 获取属性的名称 |
void set(Object obj, Object value) | 给指定对象的指定属性对象赋值 |
- AccessibleObject的常见方法
方法名 | 功能说明 |
---|---|
setAccessible(boolean flag) | 设置权限,比如给私有属性赋值需要开启权限,否则不能赋值 |
第4节 Constructor
1 | 描述构造器的类 |
- Constructor类的常见方法
方法名 | 功能说明 |
---|---|
int getModifiers() | 获取构造方法的权限修饰符 |
String getName() | 获取构造方法的名称 |
Class<?>[] getParameterTypes() | 方法的参数列表类型 |
T newInstance(Object… initargs) | 构造方法 |
第5节 其他类和方法
- ClassLoader类加载器
1 2 3 4 5 | 类加载器的功能:把类(class)装载进内存中 JVM在运行时会产生3个类加载器 1. 引导类加载器:用C++编写的,是JVM自带的类加载器,负责加载Java平台核心类库 2. 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库 3. 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作 |
- 类加载的过程
- 类加载器的获取
1 | Class类中提供了获取类加载器的方法,所以要获取一个类的类加载器首先就是获取这个类的Class实例,然后调用类加载器方法获取类加载器 |
- 类加载器中的重要方法
1 2 3 | ClassLoader cl = TestDemo.class.getClassLoader(); //可以获取一个文件的输入流 InputStream in = cl.getResourceAsStream("db.properties"); |
第三章 动态代理
- 代理模式的定义
1 2 3 4 | 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用 1. 目标代理对象(源对象) 2. 代理对象 |
-
静态代理的实现
-
- 公共接口
1 2 3 4 5 6
public interface Boss { /* 签字 */ void sign(); }
- IT老板
1 2 3 4 5 6 7 8 9
/* 目标代理类 */ public class ItBoss implements Boss { @Override public void sign() { System.out.println("IT老板签字..."); } }
- IT秘书
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/* 代理类 */ public class Secretary implements Boss { /* 目标代理对象 */ private Boss boss; public Secretary(Boss boss) { this.boss = boss; } @Override public void sign() { /* 代理对象方法,调用目标代理对象方法 */ boss.sign(); } }
-
静态代理的局限
1 | 静态代理设计,每一个代理类只能代理一个接口,如果在项目中需要对多个接口生成代理,这样程序开发中就会产生过多代理不易维护. |
-
动态代理的实现
-
- JDK动态代理
1 2 3
JDK自带的动态代理类java.lang.reflect.Proxy实现动态代理 优点: 简单、方便 缺点: 只能代理接口,不能代理类
- CGLIB动态代理
1 2
开源,功能强大高性能的代码生成库 优点: 可以代理类
目标代理类
1 2 3 4 5 6
public class ITBoss { //签名 void sign() { System.out.println("IT老板签名..."); } }
测试
```java
public class TestDemo01 {
public static void main(String[] args) {//1.创建Enhancer对象 Enhancer enhancer = new Enhancer(); //2.指定被代理对象的Class enhancer.setSuperclass(ITBoss.class); //3.设置方法的拦截以及回调 enhancer.setCallback(new MethodInterceptor() { /* * obj:被代理对象 * method:原方法 * args:方法入参 * methodProxy:代理的方法 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(obj, args); } }); //创建代理对象 ITBoss boss = (ITBoss) enhancer.create(); System.out.println(boss);//指向的是代理对象com.hy.ITBoss$$EnhancerByCGLIB$$3e50753c@7506e922 boss.sign(); }