1、类加载器
1.1、类的加载
1.2、类初始化时机
1.3、类加载器
1.4、类加载器的作用
2、反射
2.1、反射机制
2.2、获取Class对象(字节码文件对象)的三种方法
2.3、通过反射获取构造方法并使用
2.4、通过反射获取成员变量并使用
2.5、通过反射获取成员方法并使用
2.6、配置文件+反射
2.7、通过反射越过泛型检查
2.8、通过反射写一个通用方法:设置某个对象的某个属性为指定的值
3、动态代理
3.1、简单使用
3.2、测试 jdk 动态代理--使用InvocationHandler 匿名内部类
3.3、测试 jdk 动态代理--创建类实现 InvocationHandler 接口
3.4、代理工厂实现 jdk 动态代理
1、类加载器 <=返回目录
1.1、类的加载 <=返回目录
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载、连接、初始化三步来实现对这个类进行初始化。
加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
连接:
验证:是否有正确的内部结构,并和其他类协调一致。
准备:负责为类的静态成员分配内存,并设置默认初始化值。
解析:将类的二进制数据中的符号引用替换为直接引用。
初始化:类的初始化。
1.2、类初始化时机 <=返回目录
(1)创建类的实例 Person p = new Person();
(2)访问类的静态变量,或为类的静态变量赋值 Person.name = "zhangsan";
(3)调用类的静态方法
(4)使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
(5)初始化某个类的子类
(6)直接使用java.exe命令来运行某个主类(包含main方法的类)
1.3、类加载器 <=返回目录
负责将 xxx.class 文件加载到内存中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
类加载器的组成(分类):
BootStrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
System ClassLoader 系统类加载器
1.4、类加载器的作用 <=返回目录
BootStrap ClassLoader 根类加载器:也被称为引导类加载器,负责java核心类的加载,比如System、String等,再jre的lib目录下rt.jar文件中。
Extension ClassLoader 扩展类加载器:负责jre的扩展目录ext中jar包的加载。
System ClassLoader 系统类加载器:负责再JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。
类加载器将 xxx.class 文件加载到内存中,并为之生成对应的Class对象。那么,Class对象有什么用呢?如何用呢?这就是反射要研究的内容。
2、反射 <=返回目录
2.1、反射机制 <=返回目录
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以先要获取到每一个字节码文件对应的Class类型的对象。
2.2、获取Class对象(字节码文件对象)的三种方法 <=返回目录
// 第一种 对象.getClass() Person p = new Person(); Class c = p.getClass(); // 第二种 类名.class Class c2 = Person.class; // 第三种 将类名作为字符串传递给Class类中的静态方法forName Class c3 = Class.forName("com.oy.Person");
// 任意数据类型都具备一个class静态属性 Class intType = int.class; System.out.println("int类型的名字:" + intType.getName()); // int类型的名字:int Class integerType = Integer.class; System.out.println("Integer类型的名字:" + integerType.getName()); // Integer类型的名字:java.lang.Integer
2.3、通过反射获取构造方法并使用 <=返回目录
Person类
public class Person { public Integer id; private String name; private Integer age; private void show(String name) { System.out.println("name: " + name); } public void show(Integer age) { System.out.println("age: " + age); } public Person() {} public Person(String name) { this.name = name; } private Person(Integer age) { this.age = age; } public Person(String name, Integer age) { this.name = name; this.age = age; } // getter和setter方法省略 @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
测试类
package com.oy.test; import java.lang.reflect.Constructor; import com.oy.model.Person; public class Demo { public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.oy.model.Person"); // public Constructor[] getConstructors():获取所有公共构造方法 // public Constructor[] getDeclaredConstructors():获取所有构造方法 Constructor[] Constructors = clazz.getConstructors(); for (Constructor con : Constructors) { System.out.println(con); } // 获取单个构造方法 // public Constructor<T> getConstructor(Class<?>... parameterTypes) // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象 Constructor con1 = clazz.getConstructor(); System.out.println(con1); // public com.oy.model.Person() Person p1 = (Person)con1.newInstance(); //java.lang.IllegalArgumentException: wrong number of arguments // Person p1 = (Person)clazz.getConstructor(String.class); System.out.println(p1); // Person [name=null, age=null] Constructor con2 = clazz.getConstructor(String.class); System.out.println(con2); // public com.oy.model.Person(java.lang.String) Person p2 = (Person)con2.newInstance("张三"); System.out.println(p2); // Person [name=张三, age=null] Constructor con3 = clazz.getConstructor(String.class, Integer.class); System.out.println(con3); // public com.oy.model.Person(java.lang.String,java.lang.Integer) Person p3 = (Person)con3.newInstance("张三", 10); System.out.println(p3); // Person [name=张三, age=10] } }
通过反射获取私有构造方法并使用
Class clazz = Class.forName("com.oy.model.Person"); Constructor con = clazz.getDeclaredConstructor(Integer.class); // 没有下面这句,报错java.lang.IllegalAccessException con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查 Person p = (Person) con.newInstance(20); System.out.println(p); // Person [name=null, age=20]
2.4、通过反射获取成员变量并使用 <=返回目录
为了测试,给Person类添加一个public字段
public Integer id;
通过反射获取成员变量并使用
Class clazz = Class.forName("com.oy.model.Person"); // Field[] fields = clazz.getFields(); // 获取所有公共的成员变量 Field[] fields = clazz.getDeclaredFields(); // 获取所有的成员变量 for (Field field : fields) { System.out.println(field); } // 通过无参构造方法创建对象 Constructor con = clazz.getConstructor(); Object obj = con.newInstance(); // 获取单个的成员变量 // 获取public字段: id, 并对其赋值 Field idField = clazz.getField("id"); idField.set(obj, 1); System.out.println(obj); // Person [id=1, name=null, age=null] // 获取private字段: name, 并对其赋值 Field nameField = clazz.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(obj, "张三"); System.out.println(obj); // Person [id=1, name=张三, age=null]
2.5、通过反射获取成员方法并使用 <=返回目录
Class clazz = Class.forName("com.oy.model.Person"); // Method[] methods = clazz.getMethods(); // 获取自己的包括父亲的公共方法 Method[] methods = clazz.getDeclaredMethods(); // 获取自己的所有的方法 for (Method method : methods) { System.out.println(method); } // 通过无参构造方法创建对象 Constructor con = clazz.getConstructor(); Object obj = con.newInstance(); // 获取单个方法并使用 Method method1 = clazz.getMethod("show", Integer.class); method1.invoke(obj, 100); // 获取私有方法并使用 Method method2 = clazz.getDeclaredMethod("show", String.class); method2.setAccessible(true); method2.invoke(obj, "张三"); // 通过setXxx()方法给字段赋值 String fieldName = "age"; fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); Method method3 = clazz.getMethod("set" + fieldName, Integer.class); method3.invoke(obj, 200); System.out.println(obj); // Person [id=null, name=null, age=200]
2.6、配置文件+反射 <=返回目录
package com.oy.test;
import java.io.FileReader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Properties; public class Demo { public static void main(String[] args) throws Exception { // 加载键值对数据 Properties prop = new Properties(); FileReader fr = new FileReader("config.properties"); // 文件位于项目路径下 prop.load(fr); fr.close(); // 获取数据 String className = prop.getProperty("className"); String methodName = prop.getProperty("methodName"); System.out.println("className: " + className + ", methodName: " + methodName); // 获取字节码文件对象 Class clazz = Class.forName(className); // 通过无参构造方法创建对象 // Constructor con = clazz.getConstructor(); // Object obj = con.newInstance(); Object obj = clazz.newInstance(); Method method = clazz.getMethod(methodName, Integer.class); method.invoke(obj, 300); } }
配置文件 config.properties
className=com.oy.model.Person
methodName=show
2.7、通过反射越过泛型检查 <=返回目录
/* * 给你一个ArrayList<Integer>对象,在这个集合中添加一个字符串数据,如何实现呢? */ public class ArrayListDemo { public static void main(String[] args) throws Exception { // 创建集合对象 ArrayList<Integer> array = new ArrayList<Integer>(); Class c = array.getClass(); // 集合ArrayList的class文件对象 Method m = c.getMethod("add", Object.class); m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello m.invoke(array, "world"); m.invoke(array, "java"); System.out.println(array); } }
2.8、通过反射写一个通用方法:设置某个对象的某个属性为指定的值 <=返回目录
package com.oy.test; import java.lang.reflect.Field; public class Utils { // 给obj对象的propertyName属性赋值为value public static void setProperty(Object obj, String propertyName, Object value) throws Exception { // 根据对象获取字节码文件对象 Class<?> clazz = obj.getClass(); // 获取该对象的propertyName成员变量 Field field = clazz.getDeclaredField(propertyName); // 取消访问检查 field.setAccessible(true); // 给对象的成员变量赋值为指定的值 field.set(obj, value); } }
测试类:
package com.oy.test; import com.oy.model.Person; public class Demo { public static void main(String[] args) throws Exception { Person p = new Person(); Utils.setProperty(p, "id", 1); System.out.println(p); // Person [id=1, name=null, age=null] Utils.setProperty(p, "name", "张三"); System.out.println(p); // Person [id=1, name=张三, age=null] Utils.setProperty(p, "age", 10); System.out.println(p); // Person [id=1, name=张三, age=10] } }
3、动态代理 <=返回目录
3.1、简单使用 <=返回目录
接口
public interface UserDao { void getUserById(Integer id); }
实现类
public class UserDaoImpl implements UserDao { @Override public void getUserById(Integer id) { System.out.println("查询user..."); } }
测试jdk动态代理
package com.oy.test; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { // 创建被代理对象 final UserDao userDao = new UserDaoImpl(); UserDao proxy = (UserDao) Proxy.newProxyInstance( userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before..."); Object result = method.invoke(userDao, args); System.out.println("after..."); return result; } } ); // 代理对象调用方法 proxy.getUserById(1); } }
打印结果
before...
查询user...
after...
3.2、测试 jdk 动态代理--使用InvocationHandler 匿名内部类 <=返回目录
InvocationHandler 匿名内部类:
UserDao:
public interface UserDao {
void add();
void delete();
void update();
void find();
}
UserDaoImpl:
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加。。。");
}
@Override
public void delete() {
System.out.println("删除。。。");
}
@Override
public void update() {
System.out.println("修改。。。");
}
@Override
public void find() {
System.out.println("查询。。。");
}
}
TestProxy:
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 测试 jdk 动态代理
*/
public class TestProxy {
public static void main(String[] args) {
final UserDao userDao = new UserDaoImpl();
UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance(
userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println(proxy.getClass().getName()); // com.sun.proxy.$Proxy0
System.out.println("权限校验");
Object result = method.invoke(userDao, args);
System.out.println("日志记录");
return result;
}
});
// 动态代理对象的类型:com.sun.proxy.$Proxy0
// System.out.println("动态代理对象的类型:" + proxyUserDao.getClass().getName());
proxyUserDao.add();
proxyUserDao.find();
}
}
3.3、测试 jdk 动态代理--创建类实现 InvocationHandler 接口 <=返回目录
创建类实现 InvocationHandler 接口
UserDaoProxyHandler:
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class UserDaoProxyHandler implements InvocationHandler {
private UserDao userDao;
public UserDaoProxyHandler(UserDao userDao) {
this.userDao = userDao;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println(proxy.getClass().getName()); // com.sun.proxy.$Proxy0
System.out.println("权限校验");
Object result = method.invoke(userDao, args);
System.out.println("日志记录");
return result;
}
}
TestProxy:
package com.proxy;
import java.lang.reflect.Proxy;
/**
* 测试 jdk 动态代理
*/
public class TestProxy {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
userDao.getClass().getInterfaces(), new UserDaoProxyHandler(userDao));
// 动态代理对象的类型:com.sun.proxy.$Proxy0
// System.out.println("动态代理对象的类型:" + proxyUserDao.getClass().getName());
proxyUserDao.add();
proxyUserDao.find();
}
}
3.4、代理工厂实现 jdk 动态代理 <=返回目录
UserDao
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public interface UserDao { void getUserById(Integer id); }
UserDaoImpl
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class UserDaoImpl implements UserDao { @Override public void getUserById(Integer id) { System.out.println("查询user..."); } }
BeforeAdvice
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 前置通知 * @author oy * @version 1.0 * @date 2020年4月7日 * @time 上午11:36:59 */ public interface BeforeAdvice { void before(); }
AfterAdvice
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * 后置通知 * @author oy * @version 1.0 * @date 2020年4月7日 * @time 上午11:36:45 */ public interface AfterAdvice { void after(); }
ProxyFactory
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.oy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyFactory<T> { private T target; private BeforeAdvice beforeAdvice; private AfterAdvice afterAdvice; @SuppressWarnings("unchecked") public T createProxy() { if (target == null) return null; T proxy = (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 执行前置增强 if (beforeAdvice != null) beforeAdvice.before(); // 执行目标对象的目标方法 Object result = method.invoke(target, args); // 执行后置增强 if (afterAdvice != null) afterAdvice.after(); return result; } }); return proxy; } public void setTarget(T target) { this.target = target; } public void setBeforeAdvice(BeforeAdvice beforeAdvice) { this.beforeAdvice = beforeAdvice; } public void setAfterAdvice(AfterAdvice afterAdvice) { this.afterAdvice = afterAdvice; } }
TestProxy
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.oy; public class TestProxy { public static void main(String[] args) { // 创建被代理对象 UserDao target = new UserDaoImpl(); // 创建代理工厂 ProxyFactory<UserDao> factory = new ProxyFactory<>(); factory.setTarget(target); factory.setBeforeAdvice(new BeforeAdvice() { @Override public void before() { System.out.println("ProxyFactory before..."); } }); factory.setAfterAdvice(new AfterAdvice() { @Override public void after() { System.out.println("ProxyFactory after..."); } }); // 创建代理对象 UserDao userDapProxy = factory.createProxy(); userDapProxy.getUserById(1); } }
---