Java反射&动态代理 反射机制
Java 反射(Reflection)是一种机制,它允许 Java 程序在运行时获取和操作它本身的数据结构,比如类、方法、属性等。通过反射,我们可以动态地创建对象、调用方法、访问属性等,而无需在编译时知道这些信息。
Java 反射主要包括以下几个核心类:
Class 类:表示一个类或接口,包含了获取类信息的方法,如获取类名、父类、接口、属性、方法等。
Constructor 类:表示一个构造函数,包含了获取构造函数信息的方法,如获取构造函数名、参数列表等。
Field 类:表示一个属性,包含了获取属性信息的方法,如获取属性名、类型、访问权限等。
Method 类:表示一个方法,包含了获取方法信息的方法,如获取方法名、参数列表、返回类型等。
以下是一些 Java 反射的常见用法:
获取类信息:通过 Class.forName()
方法获取某个类的 Class
对象,然后使用 Class
对象的各种方法获取类的信息,如 getName()
获取类名,getDeclaredMethods()
获取所有方法等。
创建对象:通过 Class
对象的 getConstructor()
或 getDeclaredConstructor()
方法获取指定构造函数的引用,然后使用 newInstance()
或 newInstance()
方法创建对象。
访问属性:通过 Class
对象的 getDeclaredField()
方法获取指定属性的引用,然后使用 set()
或 get()
方法设置或获取属性的值。
调用方法:通过 Class
对象的 getDeclaredMethod()
方法获取指定方法的引用,然后使用 invoke()
方法调用方法并传递参数。
动态代理:通过 Java 反射实现动态代理,可以在运行时创建一个实现了指定接口的代理类,并实现指定的方法逻辑。
Class
类就是通过Field
和Method
来描述类中的字段和方法
代码 Person 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package net.Seck2y.a02;public class Person { private String name = "zhangsan" ; private int age = 23 ; public Person () {} public Person (String name, int age) { this .name = name; this .age = age; } public void action (String string) { System.out.println(string); } @Override public String toString () { return "Person{" + "name: " + this .name + ", age: " + this .age + "}" ; } }
Reflection 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 package net.Seck2y.a02;import java.lang.reflect.*;public class Reflection { public static void main (String[] args) throws Exception { Class<?> personClass = Class.forName("net.Seck2y.a02.Person" ); Constructor<?> constructor = personClass.getConstructor(String.class, int .class); Object person = constructor.newInstance("lisi" , 24 ); System.out.println(person); Field[] personField = personClass.getDeclaredFields(); for (Field f:personField){ System.out.println(f); } Field nameField = personClass.getDeclaredField("name" ); Field ageField = personClass.getDeclaredField("age" ); nameField.setAccessible(true ); ageField.setAccessible(true ); String name = (String) nameField.get(person); int age = (int ) ageField.get(person); System.out.println( nameField.getName() + ": " + name + ", " + ageField.getName() + ": " + age); Field setName = personClass.getDeclaredField("name" ); Field setAge = personClass.getDeclaredField("age" ); setName.setAccessible(true ); setAge.setAccessible(true ); setName.set(person, "wangwu" ); setAge.set(person, 25 ); System.out.println( setName.getName() + ": " +setName.get(person) + ", " + setAge.getName() + ": " + setAge.get(person)); Method[] personMethod = personClass.getDeclaredMethods(); for (Method m: personMethod) { System.out.println(m); } Method actionMethod = personClass.getMethod("action" ,String.class); actionMethod.invoke(person,"Reflection" ); } }
Class java.lang.Class类
获取对象
1 2 3 obj.getClass(); obj.class; Class.forName(obj);
方法
1 2 3 4 5 6 7 8 9 10 11 12 getName:获取全类名 getSimpleName:获取简单类名 getFields:获取所有public修饰的属性,包含本类以及父类的 getDeclaredFields:获取本类中所有属性 getMethods:获取所有public修饰的方法,包含本类以及父类的 getDeclaredMethods:获取本类中所有方法 getConstructors:获取本类所有public修饰的构造器 getDeclaredConstructors:获取本类中所有构造器 getPackage:以Package形式返回包信息 getSuperClass:以Class形式返回父类信息 getInterfaces:以Class[]形式返回接口信息 getAnnotations:以Annotation[]形式返回注解信息
Constructor 获取无参构造方法 Java 1.9 版本中被弃用,还可以用
1 2 3 personClass.newInstance();
获取类的构造方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Class<?> personClass = Class.forName("net.Seck2y.a02.Person" ); Constructor<?> constructor = personClass.getConstructor(String.class, int .class); Object person = constructor.newInstance("lisi" , 24 );System.out.println(person); net.Seck2y.a02.Person@4eec7777
Field
(public)
getField(String name)
只能获取一个指定类或其父类中的公共字段
getFields()
会返回一个包含所有公共字段的数组
(public, private, protect)
getDeclaredField(String name)
只能获取指定类中的一个字段对象
getDeclaredFields()
会返回一个包含所有字段的数组
私有成员和方法,不能直接访问
setAccessible(true)
方法是用于打破访问限制的方法,它允许访问私有字段、私有方法和私有构造函数
获取成员属性的信息(无值) 1 2 3 4 5 6 7 8 9 Field[] personField = persClass.getDeclaredFields(); for (Field f:personField){ System.out.println(f); } private java.lang.String net.Seck2y.a02.Person.nameprivate int net.Seck2y.a02.Person.age
获取成员属性的名称和值 1 2 3 4 5 6 7 8 9 10 11 Field nameField = personClass.getDeclaredField("name" );Field ageField = personClass.getDeclaredField("age" );nameField.setAccessible(true ); ageField.setAccessible(true ); String name = (String) nameField.get(person); int age = (int ) ageField.get(person); System.out.println(nameField.getName() + ": " + name + ", " + ageField.getName() + ": " + age);
修改成员属性的值 1 2 3 4 5 6 7 8 9 10 11 Field setName = personClass.getDeclaredField("name" );Field setAge = personClass.getDeclaredField("age" );setName.setAccessible(true ); setAge.setAccessible(true ); setName.set(person, "wangwu" ); setAge.set(person, 25 ); System.out.println(setName.getName() + ": " + setName.get(person) + ", " + setAge.getName() + ": " + setAge.get(person));
Method
(public)
getMethod(String name, Class<?> ... perameterTypes)
只能获取一个指定类或其父类中的公有方法
getMethods()
会返回一个包含所有公有方法的数组
(public, private, protect)
getDeclaredMethod(String name, Class<?> ... perameterTypes)
只能获取指定类中的一个方法
getDeclaredMethods()
会返回一个包含所有方法的数组
getEnclosingMethod()
获取当前方法所属的类及方法信息,当一个方法被调用时,如果该方法不属于任何一个类的方法,或者属于一个静态方法,那么 getEnclosingMethod()
方法将返回 null
私有成员和方法,不能直接访问
setAccessible(true)
方法是用于打破访问限制的方法,它允许访问私有字段、私有方法和私有构造函数
获取方法 1 2 3 4 5 6 7 8 9 Method[] personMethod = personClass.getDeclaredMethods(); for (Method m: personMethod) { System.out.println(m); } public java.lang.String net.Seck2y.a02.Person.toString()public void net.Seck2y.a02.Person.action(java.lang.String)
getMethods
可以获取包括父类的共有方法
1 2 3 4 5 6 7 8 9 10 public java.lang.String net.Seck2y.a02.Person.toString()public void net.Seck2y.a02.Person.action(java.lang.String)public final void java.lang.Object.wait(long ,int ) throws java.lang.InterruptedExceptionpublic final void java.lang.Object.wait() throws java.lang.InterruptedExceptionpublic final native void java.lang.Object.wait(long ) throws java.lang.InterruptedExceptionpublic boolean java.lang.Object.equals(java.lang.Object)public native int java.lang.Object.hashCode()public final native java.lang.Class java.lang.Object.getClass()public final native void java.lang.Object.notify()public final native void java.lang.Object.notifyAll()
调用方法 方法 action是 public修饰,getMethod() 和 getDeclaredMethod() 都可用
1 2 3 4 Method actionMethod = personClass.getMethod("action" ,String.class);actionMethod.invoke(person,"Reflection" );
如果方法是 private修饰
1 2 3 Method actionMethod = personClass.getDeclaredMethod("action" ,String.class);actionMethod.setAccessible(true ); actionMethod.invoke(person,"Reflection" );
动态代理 Java
反射提供了一种类动态代理机制,可以通过代理接口实现类来完成程序无侵入式扩展
代码 Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Test { public static void main (String[] args) { BigStar bigStar = new BigStar ("鸡哥" ); Star proxy = ProxyUtil.createProxy(bigStar); String result = proxy.sing("只因你太美" ); System.out.println(result); } }
ProxyUtil 代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class ProxyUtil { public static Star createProxy (BigStar bigStar) { Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), new Class []{Star.class}, new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { if ("sing" .equals(method.getName())){ System.out.println("准备话筒,收钱" ); }else if ("dance" .equals(method.getName())){ System.out.println("准备场地,收钱" ); } return method.invoke(bigStar,args); } } ); return star; } }
Star 接口
1 2 3 4 5 6 7 public interface Star { public abstract String sing (String name) ; public abstract void dance () ; }
BigStar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class BigStar implements Star { private String name; public BigStar () { } public BigStar (String name) { this .name = name; } @Override public String sing (String name) { System.out.println(this .name + "正在唱" + name); return "谢谢" ; } @Override public void dance () { System.out.println(this .name + "正在跳舞" ); } public String getName () {a return name; } public void setName (String name) { this .name = name; } public String toString () { return "BigStar{name = " + name + "}" ; } }
ProxyUtil 拦截方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ProxyUtil { public static Star createProxy (BigStar bigStar) { public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) Star star = (Star) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), new Class []{Star.class}, new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { if ("cleanWC" .equals(method.getName())){ System.out.println("拦截,不调用大明星的方法" ); return null ; } return method.invoke(bigStar,args); } } ); return star; } }