Java-day11-Reflect和动态代理

  •  反射

  •  定义:动态获取类的字节码文件,并对其成员进行抽象

        整体含义:就是通过字节码文件直接创建对象

  •  过程:

         1.获取字节码文件对象

         2.通过字节码文件对象获取对应的实例对象

         3.给属性赋值(通过从属性中提取出来的类---Field)

         4.调用方法(通过从方法中提取的类--Method)

  • 原理

  •  获取字节码文件对象

         1.通过Object提供的getClass()方法。(首先必须要有一个对象  XXX)

         2.通过每种数据类型都有的一个class属性  (在使用的位置必须当前类是可见的,因为这里要显示的使用这个类名,对类的依赖性太强,使用不方便 XXX)

         3.Class类提供的一个静态方法static Class forName(String str)  str是包名加类名(我们只需要提供一个当前类的字符串形式即可)  eg:要保证至少字符串对应的类是存在的

  •  代码
package com.qf.test;

public class Demo1 {
	public static void main(String[] args) throws ClassNotFoundException {
		//1.通过Object提供的getClass()方法
		 fun1();
		//2.通过每种数据类型都有的一个class属性
		 fun2();
		//3.Class类提供的一个静态方法forName(字符串)   字符串:包名+类名
		 fun3();
	}
	public static void fun1() {
		Person person = new Person();
		Class<?> class1 = person.getClass();
		Class<?> class2 = person.getClass();
		System.out.println(class1 == class2);//true  
	}
	public static void fun2() {
		Class<?> class1 = Person.class;
		System.out.println(class1.getName());
	}
	public static void fun3() throws ClassNotFoundException {
		//注意:要保证至少字符串对应的类是存在的
		Class<?> class1 = Class.forName("com.qf.test.Person");
	}
}
  •  通过字节码文件对象获取对应的实例对象

         1.通过无参的构造方法创建实例对象   

         2.通过有参的构造方法创建实例对象

  •   代码
package com.qf.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

//2.通过字节码文件对象获取对应的实例对象
public class Demo2 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//普通方式
		//Person person = new Person();
		
		//通过反射创建普通对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		//方法一:通过无参的构造方法创建实例对象
		fun1(class1);
		//方法二:通过有参的构造方法创建实例对象
		fun2(class1);
	}
	//方法一:通过无参的构造方法创建实例对象
	public static void fun1(Class<?> cls) throws InstantiationException, IllegalAccessException {
		//创建实例对象
		//这里相当于在newInstance方法的内部调用了无参的构造方法
		Object object = cls.newInstance();
		Person person = (Person)object;
		person.setName("bingbing");
		System.out.println(person.getName());
	}
	//方法二:通过有参的构造方法创建实例对象
	public static void fun2(Class<?> cls) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//先得到有参的构造方法
		//这里要写参数的字节码文件对象形式        所有的类型都有字节码文件对象
		//相当于  public Person(String name, int age)
		Constructor constructor = cls.getConstructor(String.class,int.class);
		Object object = constructor.newInstance("bingbing",18);
		System.out.println(object);
	}
}
  • 给属性赋值(通过从属性中提取出来的类---Filed)
package com.qf.test;

import java.lang.reflect.Field;

public class Demo3 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
		Person person = new Person();
		//person.name = "bingbing";
		
		//使用反射实现
		//1.获取字节码文件对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		
		//2.获取实例对象
		Object object = class1.newInstance();
		
		//3.调用属性
		//注意:如果想使用getField,name属性必须是public的
		//Field field1 = class1.getField("name");
		//如果name是私有的,我们可以这样做   ,忽略权限
		Field field1 = class1.getDeclaredField("name");
		field1.setAccessible(true);
		//赋值
		//第一个参数:关联的具体对象
		//第二个参数:赋的值
		field1.set(object, "bing");
		
		System.out.println(field1.get(object));
	}
}
  •    调用方法(通过从方法中提取出来的类----Method)

           1.调用非静态无参 

           2.调用非静态有参

           3.调用静态有参

package com.qf.test;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Demo4 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//使用反射实现
		//1.获取字节码文件对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		
		//调用非静态无参
		fun1(class1);
		//调用非静态有参
		fun2(class1);
		//调用静态有参
		fun3(class1);
	}
	//调用非静态无参
	public static void fun1(Class<?> cla) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//2.获取实例对象
		Object object = cla.newInstance();
		//3.通过反射得到方法
		Method method = cla.getMethod("show");
		//4.调用方法,通过调用invoke方法实现
		method.invoke(object);
	}
	//调用非静态有参
	public static void fun2(Class<?> cla) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//2.先得到有参的构造方法
		Constructor<?> constructor = cla.getConstructor(String.class,int.class);
		Object object = constructor.newInstance("bingibn",10);
		
		//3.通过反射得到方法
		Method method = cla.getMethod("callPhone",String.class);
		//4.调用方法,通过调用invoke方法实现
		method.invoke(object,"110");
	}
	//调用静态有参
	public static void fun3(Class<?> cla) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//3.通过反射得到方法
		Method method = cla.getMethod("run",int.class);
		//4.调用方法,通过调用invoke方法实现
		method.invoke(null,11);
	}
}

           作用:根据OCP(对扩展开放,对修改关闭)的原则,在不改变原来类的基础上,给这个类增加额外的功能

           缺点:代理对象要保证跟目标对象实现同样的接口,在维护的时候两个对象都要维护,而且代理对象实现的接口是死的,这时如果要给想实现不同功能的多个目标对象添加代理对象的话,要添加很多个类

  •  动态代理

      动态生成代理对象的方法--通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建
      参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件
      参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了
      参数三:代理类的构造方法生成的对象--注意:指定给构造方法的参数要使用Object

       public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,  InvocationHandler h)

       代理对象调动方法的时候,invoke方法会自动被调用

package com.qf.invocation1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//使用动态代理
public class Test {
	//模拟功能:bingbing和chenchen找房住
	public static void main(String[] args) {
		//静态代理
//		Bingbing bingbing = new Bingbing();
//		//bingbing.findHouse();
//		Agent agent = new Agent(bingbing);
//		agent.findHouse();
		
		//动态代理
		TestInter testInter = new Bingbing();
		//调用动态代理的方法实现功能
		/**
		 *动态生成代理对象的方法--通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建
		 *参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件
		 *参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了
		 *参数三:代理类的构造方法生成的对象--注意:指定给构造方法的参数要使用Object
		 * 
		 */
//		TestInter object = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, new Agent(testInter));
		//代理对象调动方法的时候,invoke方法会自动被调用
//		object.findHouse();
//		
//		TestEat testEat = new Langlang();
//		TestEat object1 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new Agent(testEat));
//		object1.eat();
		
		//进一步优化----直接使用InvocationHandler创建匿名内部类干活儿,不再需要Agent类
		TestInter object2 = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, 
			new InvocationHandler() {
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					System.out.println("扣一个月的房租作为中介费");
					Object object = method.invoke(testInter, args);
					System.out.println("哈哈大笑");
					return object;
				}
		   }
		);
		object2.findHouse();
		
		TestEat testEat = new Langlang();
		TestEat object3 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new InvocationHandler() {
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("先洗后");
				Object object = method.invoke(testEat, args);
				System.out.println("哈哈大笑");
				return object;
			}
	   });
		object3.eat();
		
		//使用工厂方法
		TestInter testInter3 = TestFactory.getAgentFactory(testInter);
		testInter3.findHouse();
	}
}












       代理类实现InvocationHandler接口并实现它的invoke方法

       public Object invoke(Object proxy, Method method, Object[] args)

       eg:这个方法在调用接口方法的时候会被自动调用

       参数一:代理对象的引用

       参数二:目标对象的方法

       参数三:目标对象的方法参数

package com.qf.invocation1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Agent implements InvocationHandler{
	//先给他个人
	//注意:指定给构造方法的参数要使用Object
	Object person;
	public Agent(Object person) {
		super();
		this.person = person;
	}
//	public void findHouse() {
//		System.out.println("扣一个月的房租作为中介费");
//		person.findHouse();
//		System.out.println("哈哈大笑");
//	}
	/**
	 * 接口中的方法
	 * 主要:这个方法在调用接口方法的时候,会被自动调动
	 * 参数一:代理对象的引用
	 * 参数二:目标对象的方法
	 * 参数三:目标对象的方法参数
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {		
		System.out.println("扣一个月的房租作为中介费");
		Object object = method.invoke(person, args);
		System.out.println("哈哈大笑");
		return object;
	}
}

   目标代理对象

package com.qf.invocation1;

public class Bingbing implements TestInter {
	public void findHouse() {
		System.out.println("冰冰来西三旗找房");
	}
}

 

package com.qf.invocation1;

public class ChenChen implements TestInter {
	public void findHouse() {
		System.out.println("晨晨去日本找房");
	}
}

 

package com.qf.invocation1;

public class Langlang implements TestEat{
	@Override
	public void eat() {
		System.out.println("郎朗吃饭");
		
	}
}

   目标对象的接口

package com.qf.invocation1;

public interface TestInter {
	public void findHouse();
}

 

package com.qf.invocation1;

public interface TestEat {
	public void eat();
}
  •  创建一个工厂类--------用于创建代理对象
package com.qf.invocation1;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//创建一个工厂类---用于创建代理对象
public class TestFactory {
	//工厂方法
	public static TestInter getAgentFactory( final TestInter test) {
  //final TestInter test = new Bingbing();
		
		TestInter agent = (TestInter)Proxy.newProxyInstance(test.getClass().getClassLoader(), new Class[]{TestInter.class}, new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				// TODO Auto-generated method stub
				System.out.println("扣一半房租做中介费");
				// TODO Auto-generated method stub
				//通过反射的方法调用具体对象的方法
				Object object = method.invoke(test, args);
				
				System.out.println("哈哈大笑");
				
				return object;
			}
		});
		
		return agent;
	}

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值