一、反射
1、概述:
JAVA反射机制是在运行状态中,对于任意一个类,都能够创建该类对象,调用这个类的所有属性和方法包括构造方法;
2、字节码文件
1)概述:
类加载器负责将.class文件加载到内在中,并为之生成对应的Class对象
2)字节码文件对象的三种获取方式
A:Object类的getClass()方法
B:所有类包括基本数据类型的静态属性class
如:int.class; String.class
C:Class类中静态方法forName(String className) //参数:className - 所需类的完全限定名
3、Class类
1)获取构造器:
获取其类全部构造器:返回表示此类构造方法的 Constructor 对象数组
public Constructor>[] getConstructors() //只能获取其公共构造器
public Constructor>[] getDeclaredConstructors() //获取所有构造器包括私有
获取其类一个构造器:
参数:可变参数,参数数组,传入需要调用的构造器的参数的字节码文件(类型.class)
返回值:与指定的 parameterTypes 相匹配的构造方法的 Constructor 对象
public Constructor
public Constructor
通过获取的构造器调用newInstance(Object... initargs)方法就可以创建该类对象
通过Class类的public T newInstance()方法也可以用来创建该类的无参对象
2)获取属性
获取所有成员变量:返回表示字段的 Field 对象的数组
public Field[] getFields() //只能获取其公共属性
public Field[] getDeclaredFields() //获取所有属性
获取单个成员变量
参数:需要获取的属性的名称
返回值:由 name 指定的该类的 Field 对象
public Field getField(String name) //只能获取其公共属性
public Field getDeclaredField(String name) //获取所有属性
使用Field的public void set(Object obj,Object value)方法可以给该属性赋值
参数: obj:应该修改其字段的对象
value:正被修改的 obj 的字段的新值
3)获取成员方法
获取所有成员方法:表示此类中方法的 Method 对象的数组
public Method[] getMethods() //获取所有的共有的方法,包括父类的公共方法
public Method[] getDeclaredMethods() //获取所有的方法对象,包括私有的
获取单个成员方法
public Method getMethod(String name,Class>... parameterTypes) //获取指定的方法对象
public Method getDeclaredMethod(String name,Class>... parameterTypes) //获取包括私有的方法对象
使用Method的public Object invoke(Object obj,Object... args)调用方法
参数: obj:从中调用底层方法的对象
Object... args:该方法的参数
4、取消语法检查
1)AccessibleObject类 —— 是 Field、Method 和 Constructor 对象的基类
直接已知子类:Constructor, Field, Method
2)public void setAccessible(boolean flag)throws SecurityException
当flag是true的时候则指示反射的对象在使用时应该取消 Java 语言访问检查
3)使用:
在使用反射创建类的私有化对象、给私有化属性赋值、调用私有化方法的时候,需要先调用此方法,取消语法检查;
就是执行newInstance()、set()、invoke()前调用setAccessible(true)
5、运行配置文件
import java.io.FileInputStream; import java.lang.reflect.Method; import java.util.Properties; //通过反射运行配置文件内容 public class Test { public static void main(String[] args) throws Exception { //将配置文件读取到Properties集合中 Properties pro = new Properties(); pro.load(new FileInputStream("a.txt")); //通过键找值获取到需要创建对象的类的完全限定名,获取其字节码文件对象 Class> clazz = Class.forName(pro.getProperty("classname")); //通过键找值获取到需要调用的成员方法 Method met = clazz.getMethod(pro.getProperty("methodname")); //执行 met.invoke(clazz.newInstance()); } } public class Student { public void show(){ System.out.println("这是学生类的show方法"); } public void method(){ System.out.println("这是学生类的method方法"); } } public class Teacher { public void show(){ System.out.println("这是老师类的show方法"); } public void method(){ System.out.println("这是老师类的method方法"); } }
---------------------------------------------------------
当前项目下的a.txt配置文件
classname = 所需类的完全限定名
methodname = show
---------------------------------------------------------
需要修改时候只需改变其配置文件的值
6、越过泛型检查
import java.lang.reflect.Method; import java.util.ArrayList; public class ArrayListDemo { public static void main(String[] args) throws Exception{ ArrayListal = new ArrayList (); al.add("Hello"); al.add("java"); //想要加入一个int类型的数10 //获取其字节码文件对象 Class> clazz = al.getClass(); //调用add方法 Method m = clazz.getMethod("add", Object.class); //取消语法检查 m.setAccessible(true); //添加10,并遍历 m.invoke(al, 10); for(Object o : al){ System.out.println(o); } } }
7、动态代理
1、概述:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象
在Java中提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象
2、Proxy类 —— 生成代理对象JDK提供的代理只能针对接口做代理
public static Object newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)
// 参数1:类加载器 通过Class类的getClassLoader()调用
// 参数2:类加载器对应的接口数组 通过Class的getInterfaces()调用
// 参数3:你要让这个代理对象帮你干的事情
//返回值:可以强转成被代理类所实现的接口的对象,调用被代理的方法
//自定义一个类实现InvocationHandler接口,重写public Object invoke(Object proxy, Method method, Object[] args)方法
// 参数1:代理对象 Object proxy
// 参数2:被代理类里面的方法对象
// 参数3:被代理类里面的方法对象要的参数的值
//返回值:被代理类对象所表示方法的结果
3、动态代理的实现
1)用户接口类
public interface Userdao { void add(); void del(); void revise(); void look(); }
2)用户接口的实现类
public class Userdaoimpl implements Userdao{ @Override public void add() { System.out.println("增"); } @Override public void del() { System.out.println("删"); } @Override public void revise() { System.out.println("改"); } @Override public void look() { System.out.println("查"); } }
3)测试类
import java.lang.reflect.Proxy; public class UserDemo { public static void main(String[] args) { Userdaoimpl user = new Userdaoimpl(); Class extends Userdaoimpl> clazz = user.getClass(); Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),new MyInvocationHandler(user)); Userdao newuser = (Userdao) obj; newuser.add(); newuser.del(); newuser.revise(); newuser.look(); } }
4)InvocationHandler的实现类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { Object obj; public MyInvocationHandler(Object obj) { super(); this.obj = obj; } @Override public Object invoke(Object proxy, Method m, Object[] arg)throws Throwable { System.out.println("权限校验"); Object object = m.invoke(obj, arg); System.out.println("记录日志"); return object; } }