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	面向切面编程
posted @ 2022-09-02 18:05  香菇无盐  阅读(33)  评论(0)    收藏  举报