java学习笔记018 反射
1.java.lang.Class
获取Class对象的四种方式
//1
Class clazz1 = Person.class;
//2
Person p = new Person();
Class clazz2 = p.getClass();
//3 用得多
Class clazz3 = Class.forName("com.cg.Person");
//4
Class clazz4 = 当前类名.class.getClassLoader().loadClass("com.cg.Person")
//四个clazz的地址一致,即为同一个对象
类、接口、数组、基本数据类型、注解、void都可以获取到Class对象
2.理解类的加载过程
类的加载
java.exe命令将.class文件加载到内存中的过程,加载到内存中的类叫做运行时类,一个运行时类对应一个Class类的对象
类的加载过程
Load 加载
Link 链接 将类的二进制数据合并到JRE
Initialize 初始化
类加载器 ClassLoader
System ClassLoader 系统类加载器
//自定义类调用getClassLoader()获得系统类加载器
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
Extension ClassLoader 扩展类加载器
//系统类加载器调用getParent()获得扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
BootStap ClassLoader 引导类加载器
加载核心类库
通过类加载器读取.properties文件
eg:
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
//默认在src路径下
IputStream is = classLoader.getResourceAsStream("demo.properties");
Properties pro = new Properties();
pro.load(is);
String name = pro.getProperty("name");
3.创建运行时类的对象
eg:
Class<Person> clazz = Person.class;
//内部调用运行时类的空参构造器
//所以要求有空参构造器且权限足够,一般为public
//javabean要求提供一个public的空参构造器,便于反射调用对象和子类继承
Person p = clazz.newInstance();
4.获取运行时类的完整结构
eg:
Class clazz = Person.class;
属性Field
//此方法获取当前运行时类及其父类中public修饰的属性
Field[] fields = clazz.getFields();
//此方法获取当前运行时类中声明的所有属性(不包括从父类继承的属性)
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
//1权限修饰符
int modifier = f.getModifiers();
System.out.println(Modifier.toString(modifier));
//2数据类型
Class type = f.getType();
System.out.println(type.getName());
//3变量名
String fieldName = f.getName();
}
方法Method
//getMethods()获取当前运行时类及其父类中public修饰的方法
Method[] methods = clazz.getMethods();
//getDeclaredMethods()获取当前运行时类中声明的所有方法(不包括从父类继承的方法)
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
//1权限修饰符
int modifier = m.getModifiers();
System.out.println(Modifier.toString(modifier));
//2返回值类型
Class returnType = m.getType();
System.out.println(returnType.getName());
//3方法名
String methodName = m.getName();
//4参数列表
Class[] parameterTypes = m.getParameterTypes();
if(!(parameterTypes == null || parameterTypes.length == 0)){
for(int i=0; i<parameterTypes.length; i++){
System.out.println(parameterTypes[i].getName() + " args_" + i);
if(i < parameterTypes.length-1){
System.out.println(", ");
}
}
}
//5标记方法的注解
//只能获取RETENTION为RUNTIME的注解
Annotation[] = annos = m.getAnnotations();
//6throws的异常类
Class[] exceptionTypes = m.getExceptionTypes();
for(Class e : exceptionTypes){
System.out.println(e.getName());
}
}
构造器 Constructor
//获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
//获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
Constructor[] constructors = clazz.getDeclaredConstructors();
父类
Class superclass = clazz.getSuperclass();
带泛型的父类的泛型
Type superclass = clazz.getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) superclass;
//获取泛型参数
Type[] actualTypeArguments = paramType.getActualTypeArguments();
接口
//只包括类自己声明实现的接口
Class[] getInterfaces()
Class[] getGenericInterfaces()
包
Package package = clazz.getPackage();
5.调用运行时类的指定结果
属性
Field getField(String name)
Field getDeclaredField(String name)
Field[] getFields()
Field[] getDeclaredFields()
eg:
Class clazz = Person.class;
Person person = (Person) clazz.newInstance();
Field name = clazz.getField("name");
name.set(person, "张三");
String pName = (String) name.get(person);
Field id = clazz.getDeclaredField("id");
id.setAccessible(true);
id.set(person, 1001);
int pId = (int) id.get(person);
方法
getDeclaredMethod(String methodName, Class ... args)
//invoke()的返回值即为调用的方法的返回值
Object invoke(Object instance, Object ... args)
静态方法
Object invoke(Class clazz, Object ... args)
eg:
Method show = clazz.getDeclaredMethod("show", String.class);
show.setAccessible(true);
Object returnVal = show.invoke(person, "helloworld");
构造器
最常用的是newInstance(),其他了解即可
eg:
//getDeclaredConstructor(Class ... args);
Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
//clazz.newInstance()调空参构造器
Person person = (Person) constructor.newInstance("helloworld");
6.动态代理
代理模式回顾
//代理类
class Server implements Network{
private Network net;
public Server(Network net){
this.net = net;
}
@Override
public void overrideMethod(){
stepAhead();
net.overrideMethod();//真实的接口实现类对象
stepAfter();
}
}
动态代理
问题
如何通过被代理类动态地创建一个代理类及其对象?
通过代理类调用方法时,如何动态地调用被代理类中的同名方法?
eg:
package com.cg.reflection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author zhengcg
* @create {2022}-{09}-{02}-{17:19}
*/
public class DynamicProxyTest {
public static void main(String[] args) {
UserNetwork userNetwork = new UserNetwork();
Network proxy1 = (Network) ProxyFactory.getProxyInstance(userNetwork);
Upload proxy2 = (Upload) ProxyFactory.getProxyInstance(userNetwork);
System.out.println(proxy1 == proxy2); //false
proxy1.surfInternet();
String msg = proxy2.uploadFile();
System.out.println(msg);
}
}
interface Network{
void surfInternet();
}
interface Upload{
String uploadFile();
}
class UserNetwork implements Network, Upload {
@Override
public void surfInternet() {
System.out.println("用户开始网上冲浪");
}
@Override
public String uploadFile() {
return "用户上传了一些文件";
}
}
class ProxyFactory{
public static Object getProxyInstance(Object proxied){
//返回的代理类在调用接口中的方法时,实际会调用MyInvocationHandler中的方法
return Proxy.newProxyInstance(proxied.getClass().getClassLoader(),
proxied.getClass().getInterfaces(),
new MyInvocationHandler(proxied));
}
}
class MyInvocationHandler implements InvocationHandler{
//被代理类
private final Object proxied;
public MyInvocationHandler(Object proxied){
this.proxied = proxied;
}
@Override
//proxy:哪个代理类调用接口中的方法;method:代理类调用了接口中哪个方法;args:传给被调用方法的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用被代理类中同名方法,可以做一些前置准备工作和后置收尾工作
return method.invoke(proxied, args);
}
}
AOP与动态代理举例
AOP Aspect Orient Programming 面向切面编程