第一章 反射的概述
第1节 反射的概念
Java的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java的反射机制. |
第2节 反射理解
如果存在反射,那是不是也存在正射?如果存在正射,那么什么是正射呢?
- 白话正射
在编写代码的时,如果使用到了某一个类,首先需要了解这个类是干什么的,然后使用new关键字实例化对象.接着对这个对象进行操作,这就是正射.
Teacher t = new Teacher();//实例化
t.doWork("语文");//调用方法(操作对象)
- 白话反射
反射就是我们不知道要创建对象的类是什么,自然也就无法使用new关键字来创建对象,但是我还想创建对象
- 正射和反射的对比
/*
* 下面是使用正射和反射实现的
* 功能相同
*/
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
java.lang.Class: 描述类的类
java.lang.reflect.Method: 描述方法的类
java.lang.reflect.Field: 描述属性的类
java.lang.reflect.Constructor: 描述构造器的类
第1节 Class类
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. 使用 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类
描述方法的方法
- Method类的常见方法
方法名 | 功能说明 |
int getModifiers() | 权限修饰符 |
String getName() | 方法名 |
Class<?>[] getParameterTypes() | 方法的参数列表类型 |
Class<?>[] getReturnType() | 返回值类型 |
Object invoke(Object obj, Object… args) | 方法调用 |
第3节 Field类
描述属性的类
- Field类的常见方法
方法名 | 功能说明 |
Object get(Object obj) | 获取指定属性值 |
int getModifiers() | 获取属性的权限修饰符 |
String getName() | 获取属性的名称 |
void set(Object obj, Object value) | 给指定对象的指定属性对象赋值 |
- AccessibleObject的常见方法
方法名 | 功能说明 |
setAccessible(boolean flag) | 设置权限,比如给私有属性赋值需要开启权限,否则不能赋值 |
第4节 Constructor
描述构造器的类
- Constructor类的常见方法
方法名 | 功能说明 |
int getModifiers() | 获取构造方法的权限修饰符 |
String getName() | 获取构造方法的名称 |
Class<?>[] getParameterTypes() | 方法的参数列表类型 |
T newInstance(Object… initargs) | 构造方法 |
第5节 其他类和方法
- ClassLoader类加载器
类加载器的功能:把类(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包装入工作
- 类加载的过程
- 类加载器的获取
Class类中提供了获取类加载器的方法,所以要获取一个类的类加载器首先就是获取这个类的Class实例,然后调用类加载器方法获取类加载器
- 类加载器中的重要方法
ClassLoader cl = TestDemo.class.getClassLoader();
//可以获取一个文件的输入流
InputStream in = cl.getResourceAsStream("db.properties");
第三章 动态代理
- 代理模式的定义
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用
1. 目标代理对象(源对象)
2. 代理对象
- 静态代理的实现
- 公共接口
public interface Boss {
/*
签字
*/
void sign();
}
- IT老板
/*
目标代理类
*/
public class ItBoss implements Boss {
@Override
public void sign() {
System.out.println("IT老板签字...");
}
}
- IT秘书
/*
代理类
*/
public class Secretary implements Boss {
/*
目标代理对象
*/
private Boss boss;
public Secretary(Boss boss) {
this.boss = boss;
}
@Override
public void sign() {
/*
代理对象方法,调用目标代理对象方法
*/
boss.sign();
}
}
- 静态代理的局限
静态代理设计,每一个代理类只能代理一个接口,如果在项目中需要对多个接口生成代理,这样程序开发中就会产生过多代理不易维护.
- 动态代理的实现
- JDK动态代理
JDK自带的动态代理类java.lang.reflect.Proxy实现动态代理
优点: 简单、方便
缺点: 只能代理接口,不能代理类
- CGLIB动态代理
开源,功能强大高性能的代码生成库
优点: 可以代理类
目标代理类
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();
}