Reflection(反射)是被视为 [动态语言] 的关键,反射机制允许程序在执行期借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
Java反射机制提供的功能:
反射相关的主要API:
java.lang.Class
代表一个类java.lang.reflect.Method
代表类的方法java.lang.reflect.Field
代表类的成员变量java.lang.reflect.Constructor
代表类的构造器Class 类是"类的类"(class of classes)。如果说类是对象的抽象和集合的话,那么 Class 类就是对类的抽象和集合。
摘自《Java编程思想》
运行时类型识别(RTTI, Run-Time Type Identification)是 Java 中非常有用的机制,在 Java 运行时,RTTI 维护类的相关信息。多态(polymorphism) 是基于 RTTI 实现的。RTTI 的功能主要是由 Class类 实现的。
public final class Class<T> extends Object implements
Serializable, GenericDeclaration, Type, AnnotatedElement {...}
在Object类中定义了以下的方法,此方法将被所有子类继承:public final Class getClass()
以上的方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称。
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个结构 (class/interface/enum/annotation/primitive type/void/[]) 的有关信息。
要了解 RTTI 在 Java 中的工作原理,首先必须要知道类型信息在运行时是如何表示的。这项工作是由称为 [Class对象] 的特殊对象完成的,它包含了与类相关的信息。事实上,Class对象 就是用来创建类的所有的 "常规" 的对象的。 Java 使用 Class对象 来执行其 RTTI,即使你正在执行的是类似转型这样的操作。Class类还拥有大量的使用 RTTI 的其他方式。
类是程序的一部分,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个 Class 对象(更恰当地说,是被保存在一个同名的 .class 文件中)。为了生成这个类的对象,运行这个程序的 JVM 将使用被称为 "类加载器" 的子系统。这个待会就说。
代码演示:每一个 Class 类的对象代表一个其他的类。就比如在下面的程序中,Class 类的对象 c1 代表了 Human 类,c2 代表了 Woman 类。
public class Demo {
public static void main(String[] args) {
Human aPerson = new Human();
Class c1 = aPerson.getClass();
System.out.println(c1.getName());
Human anotherPerson = new Woman();
Class c2 = anotherPerson.getClass();
System.out.println(c2.getName());
}
}
class Human {}
class Woman extends Human {}
当我们调用对象的 getClass() 时,就得到对应 Class 对象的引用。
在c2中,即使我们将 Women 对象的引用向上转换为 Human 对象的引用,对象所指向的 Class 类对象依然是Woman。
Java 中每个对象都有相应的 Class 类对象,因此,我们随时能通过 Class 对象知道某个对象“真正”所属的类。无论我们对引用进行怎样的类型转换,对象本身所对应的 Class 对象都是同一个。当我们通过某个引用调用方法时,Java总能找到正确的 Class 类中所定义的方法,并执行该 Class 类中的代码。由于 Class 对象的存在,Java 不会因为类型的向上转换而迷失。这就是多态的原理。
btw:类可以造对象,但类本身也是一个类(Class类) 的对象。还记得静态可以直接通过 "类名." 的方式调用吗?其实这也是"对象." 式调用,不是吗。
哪些类型可以有Class对象?
public void test5() {
// Class实例可以是哪些结构?
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;
Class c6 = Override.class;
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;
int[] a = new int[10];
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
// 只要元素类型与维度一样,就是同一个Class
System.out.println(c10 == c11);
}
当程序主动使用某个类时,如果该类还未被加载到内存中,则为了使用类而做的准备工作实际包含 3 个步骤。
<clinit>()
的过程。类构造器 <clinit>()
是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)<clinit>()
在多线程环境中被正确加锁和同步public class Demo {
@Test
public void classLoaderTest() {
/*
Step2: 链接结束后 m = 0
Step3: 初始化后,m 的值由 <clinit>() 执行决定。这个 A 的类构造器<clinit>()
由类变量的赋值和静态代码块中的语句按照顺序合并产生,类似于
<clinit>() { m = 300; m = 100;}
*/
System.out.println(A.m); // 100
}
}
class A {
static {
m = 300;
}
static int m = 100;
}
我们使用 java.exe 对某个字节码文件进行解释运行,相当于将某个字节码文件加载到内存中,此过程称为"类的加载"。加载到内存中的类,我们就称为"运行时类",此运行时类,就作为Class的一个实例。
为了生成这个实例,运行这个程序的 JVM 将使用被称为 "类加载器" 的子系统。
类加载器的作用:
类加载器子系统实际上可以包含一条类加载器链,但是只有一个原生类加载器,它是 JVM 实现的一部分。原生类加载器加载的所谓的可信类,包括 Java API 类,它们通常是从本地盘加载的。在这条链中,通常不需要添加额外的类加载器,但是如果你有特殊需求(例如以某种特殊的方式加载类,以支持WebServer应用,或者在网络中下载类),那么你有一种方式可以挂接额外的类加载器。
所有的类都是在对其第一次使用时,动态加载到 JVM 中的。当程序创建第一个对类的静态成员的引用时,就会加载这个类。这个证明构造器也是类的静态方法,即使在构造器之前并没有使用 static 关键字。因此,使用 new 操作符创建类的新对象也会被当作对类的静态成员的引用。因此,Java程序在它开始运行之前并非被完全加载,其各个部分是在必须时才加载的。
类加载器首先检查这个类的 Class 对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找 .class 文件。在这个类的字节码被加载时,它们会接受验证,以确保其没有被破坏,并且不包含不良 Java 代码(这是 Java 中用于安全防范目的地的措施之一)。
一旦某个类的 Class 对象被载入内存,它就被用来创建这个类的所有对象。
@Test
public void test() {
// 1. 获取一个 [系统类加载器]
ClassLoader classloader = ClassLoader.getSystemClassLoader();
System.out.println(classloader); // sun.misc.Launcher$AppClassLoader@58644d46
// 2. 取系统类加载器的父类加载器,即 [扩展类加载器]
classloader = classloader.getParent(); // sun.misc.Launcher$ExtClassLoader@4a574795
System.out.println(classloader);
// 3. 获取扩展类加载器的父类加载器,即 [引导类加载器]
classloader = classloader.getParent();
System.out.println(classloader); // null
// 4. 测试当前类由哪个类加载器进行加载
classloader = ClassLoaderDemo.class.getClassLoader();
System.out.println(classloader); // sun.misc.Launcher$AppClassLoader@58644d46
// 5. 测试 JDK 提供的 Object 类由哪个类加载器加载
classloader = Object.class.getClassLoader();
System.out.println(classloader); // null
}
使用类加载器加载配置文件:
@Test
public void test2() throws IOException {
Properties prop = new Properties();
// 此时的文件相对于当前 Module
// FileInputStream is = new FileInputStream("jdbc.properties");
// 此时的文件相对于 src
InputStream is = ClassLoaderDemo.class.getClassLoader()
.getResourceAsStream("jdbc1.properties");
// FileInputStream is = new FileInputStream("src\\jdbc1.properties");
prop.load(is);
String user = prop.getProperty("user");
String password = prop.getProperty("password");
System.out.println(user + ":" + password);
}
使用类字面常量来生成对 Class 对象的引用,如:Class clazz = Person.class;
。
类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。另外,对于基本数据类型的包装器类,还有一个标准字段 TYPE。TYPE 字段是一个引用,指向对应的基本数据类型的 Class 对象,如下所示:
boolean.class
等价于 Boolean.TYPE
char.class
等价于 Character.TYPE
byte.class
等价于 Byte.TYPE
short.class
等价于 Short.TYPE
int.class
等价于 Integer.TYPE
long.class
等价于 Long.TYPE
float.class
等价于 Float.TYPE
double.class
等价于 Double.TYPE
void.class
等价于 Void.TYPE
注意,当使用 ".class" 来创建对 Class 对象的引用时,不会自动地初始化该 Class 对象。该方法下 Class 对象的初始化被延迟到了对静态方法(构造器隐式是静态的)或者非常数静态域进行首次引用时才执行。
已知某个类的实例,调用该实例的 getClass()
获取 Class 对象。
Person p = new Person();
Class clazz2 = p.getClass();
Class clazz3 = Class.forName("cn.edu.nuist.java.person");
这个方法是 Class 类(所有Class对象都属于这个类)的一个 static 成员。Class 对象就和其它对象一样,我们可以获取并操作它的引用(这也就是类加载器的工作)。forName()
是取得 Class 对象的引用的一种方法。它是用一个类的全类名的String作为输入参数,返回的是一个 Class 对象的引用。
该方法产生的“副作用”:如果类还没有被加载就加载它。在加载的过程中,Person 的 static 子句被执行(属性和加载器方式就不会执行)。
如果 Class.forName()
找不到你要加载的类,它会抛出 ClassNotFoundException
。
ClassLoader classLoader = ReflectionDemo.class.getClassLoader();
Class clazz4 = classLoader.loadClass("cn.edu.nuist.Person");
main()
所在的类public class InitTest {
public static void main(String[] args) {
System.out.println("staticFinal 之前");
System.out.println(B.staticFinal);
System.out.println("staticFinal 之后");
// -----------------------
System.out.println("staticFinal2 之前");
System.out.println(B.staticFinal2);
System.out.println("staticFinal2 之后");
// -----------------------
System.out.println("staticNonFinal 之前");
System.out.println(C.staticNonFinal);
System.out.println("staticNonFinal 之后");
/*
staticFinal 之前
1101
staticFinal 之后
-----------------------
staticFinal2 之前
~~~ClassB对象初始化~~~
996
staticFinal2 之后
-----------------------
staticNonFinal 之前
~~~ClassC对象初始化~~~
67
staticNonFinal 之后
*/
}
}
class B {
static {
System.out.println("~~~ClassB对象初始化~~~");
}
static final int staticFinal = 1101;
static final int staticFinal2 = (int)(Math.random()*1101);
}
class C {
static int staticNonFinal = 67;
static {
System.out.println("~~~ClassC对象初始化~~~");
}
}
如果一个 static final
值是"编译期常量",就像 B.staticFinal
那样,那么这个值不需要对所属类进行初始化就可以被读到。但是,如果只是将一个域设置为 static 和 final 的,还不足以确保这种行为,例如,对 B.staticFinal2
的访问将强制进行类的初始化,因为它不是一个编译期常量。
如果一个 static 域不是 final 的,那么在对它访问时,总是要求在它被读取之前,要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间),就像在对 C.staticNonFinal
的访问中所看到的那样。
摘自《Java编程思想》
newInstance()
的前提:getDeclaredConstructor(Class … parameterTypes)
取得本类的指定形参类型的构造器Field、Method、Constructor、Superclass、Interface、Annotation
package cn.edu.nuist.java1;
import java.util.Date;
@MyAnnotation(value="修饰类")
public class Person extends Creature<String> implements Comparable<String>, MyInterface {
private String privateAttr;
int defaultAttr;
public int publicMethod;
static {
System.out.println("Person static block");
}
public Person() {}
@MyAnnotation("修饰构造器")
private Person(String privateAttr) {
this.privateAttr = privateAttr;
}
Person(String privateAttr, int defaultAttr) {
this.privateAttr = privateAttr;
this.defaultAttr = defaultAttr;
}
<T> T typeMethod(T t, int i, double d) {
return t;
}
@MyAnnotation("修饰方法")
private void privateMethod(String nation) {
System.out.println("我的国籍是" + nation);
}
public String publicMethod(String str, Date date) throws ArithmeticException, NullPointerException{
System.out.println("publicMethod\t" + date);
return str;
}
private static void staticMethod() {
System.out.println("static Method");
}
@Override
public void info() {
System.out.println("So, tell me, Who am I?");
}
@Override
public int compareTo(String o) {
return 0;
}
@Override
public String toString() {
return "Person{" +
"privateAttr=‘" + privateAttr + ‘\‘‘ +
", defaultAttr=" + defaultAttr +
", publicMethod=" + publicMethod +
‘}‘;
}
}
package cn.edu.nuist.java2;
import cn.edu.nuist.java1.Person;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FieldTest {
@Test
public void test1() {
Class clazz = Person.class;
// getFields(): 获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
for(Field field : fields)
System.out.println(field);
System.out.println("-----------------------------");
// getDeclaredFields(): 获取当前运行时类当中声明的所有属性(不包含父类中声明的)
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields)
System.out.println(field);
}
@Test
public void test2() {
Class clazz = Person.class;
// 权限修饰符 数据类型 变量名
Field[] declaredFields = clazz.getDeclaredFields();
for(Field field : declaredFields) {
// 1. 权限修饰符
int modifier = field.getModifiers();
System.out.print(Modifier.toString(modifier) + " ");
// 2. 数据类型
Class type = field.getType();
System.out.print(type.getName() +" ");
// 3. 变量名
String fieldName = field.getName();
System.out.println(fieldName);
}
}
}
package cn.edu.nuist.java2;
import cn.edu.nuist.java1.Person;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class MethodTest {
@Test
public void test1() {
Class clazz = Person.class;
// getMethods(): 获取当前运行时类及其所有父类当中声明为public权限的方法
Method[] methods = clazz.getMethods();
for(Method m : methods)
System.out.println(m);
System.out.println("---------------------------");
// 获取当前运行时类中声明的所有方法(不包含父类中声明的)
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods)
System.out.println(m);
}
// @Xxx
// 权限修饰符 返回值类型 方法名(参数类型1 形参名1, ...) throws XxxException {}
@Test
public void test2() {
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods) {
// 1. 获取方法声明的注解
Annotation[] annotations = m.getAnnotations();
for(Annotation a : annotations)
System.out.println(a);
// 2. 权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + " ");
// 3. 返回值类型
System.out.print(m.getReturnType() + " ");
// 4. 方法名
System.out.print(m.getName());
// 5. 形参
System.out.print("(");
Class[] paramsType = m.getParameterTypes();
if(!(paramsType == null || paramsType.length == 0)) {
int i;
for(i = 0; i < paramsType.length-1; i++)
System.out.print(paramsType[i].getName() + " args_" + i + ", ");
System.out.print(paramsType[i].getName() + " args_" + i);
}
System.out.print(") ");
// 6. 方法抛出的异常
Class<?>[] exceptionTypes = m.getExceptionTypes();
if(!((exceptionTypes == null || exceptionTypes.length == 0))) {
System.out.print("throws ");
for(int i = 0; i < exceptionTypes.length; i++) {
if(i == exceptionTypes.length-1) {
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ", ");
}
}
System.out.println();
}
}
}
package cn.edu.nuist.java2;
import cn.edu.nuist.java1.Person;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class OtherTest {
@Test
public void constructors() {
// 获取构造器
Class clazz = Person.class;
// getConstructors(): 获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor c : constructors) {
System.out.println(c);
}
System.out.println("---------------------------");
// getDeclaredConstructors(): 获取当前运行时类中所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor c : declaredConstructors)
System.out.println(c);
}
@Test
public void father() {
// 父类
Class clazz = Person.class;
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
// 带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);
// 父类的泛型
ParameterizedType paramType = (ParameterizedType) genericSuperclass;
// 获取泛型类型
Type[] actualTypeArguments = paramType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
System.out.println(((Class) actualTypeArguments[0]).getName());
}
@Test
public void interfaces() {
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for(Class c : interfaces)
System.out.println(c);
System.out.println("-----------------------");
// 父类实现的接口
Class[] interfaces1 = clazz.getSuperclass().getInterfaces();
for(Class c : interfaces1)
System.out.println(c);
}
@Test
public void pack() {
Class clazz = Person.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
@Test
public void classAnnotations() {
Class clazz = Person.class;
Annotation[] annotations = clazz.getAnnotations();
for(Annotation a : annotations)
System.out.println(a);
}
}
public class InvokeDemo {
@Test
public void invokeField() throws Exception {
Class clazz = Person.class;
// 创建运行时类的对象
Person p = (Person) clazz.newInstance();
// 获取指定的属性(要求必须是声明为public的),所以不咋用
Field publicAttr = clazz.getField("publicAttr");
// 设置当前属性的值
publicAttr.set(p, 1101);
// 获取当前对象的指定属性值
int pAttr = (int) publicAttr.get(p);
System.out.println(pAttr);
}
@Test
public void invokeField2() throws Exception {
Class clazz = Person.class;
// 创建运行时类的对象
Person p = (Person) clazz.newInstance();
Field privateAttr = clazz.getDeclaredField("privateAttr");
// 不加↓,报的不是NoSuchFieldException,而是IllegalAccessException
privateAttr.setAccessible(true); // 表示当前属性是可访问的
// 设置当前属性的值
privateAttr.set(p, "LJQ");
// 获取当前对象的指定属性值
String name = (String) privateAttr.get(p);
System.out.println(name);
}
}
public class InvokeDemo2 {
@Test
public void invokeMethod() throws Exception {
Class clazz = Person.class;
// 创建运行时类的对象
Person p = (Person) clazz.newInstance();
// 1. 获取指定的某个方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class);
// 2. 保证当前方法是可访问的
privateMethod.setAccessible(true);
// 3. 调用Method对象的invoke(),该方法的返回值即为对应方法的返回值
Object result = privateMethod.invoke(p, "China");
System.out.println(result); // void 返回 null
}
@Test
public void invokeStaticMethod() throws Exception {
Class clazz = Person.class;
Method staticMethod = clazz.getDeclaredMethod("staticMethod");
staticMethod.setAccessible(true);
// 静态方法,除了传Class对象,传 null 也OK
// 非静态方法才需要知道要调哪个对象的,静态方法不需要
staticMethod.invoke(null);
}
@Test
public void invokeConstructor() throws Exception {
Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class);
constructor.setAccessible(true);
Object o = constructor.newInstance("LiuJiaQi");
System.out.println(o);
}
}
使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
动态代理使用场合:① 调试 ② 远程方法调用
动态代理相比于静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。
由程序员创建或特定工具自动生成源代码,再对其进行编译。在程序运行之前,代理类.class文件就已经被创建,代理类和委托类的关系在运行前就确定。
public class StaticProxyDemo {
public static void main(String[] args) {
NikeClothFactory nike = new NikeClothFactory();
ProxyClothFactory proxy = new ProxyClothFactory(nike);
proxy.produceCloth();
}
}
interface ClothFactory {
void produceCloth();
}
// 代理类
class ProxyClothFactory implements ClothFactory {
private ClothFactory factory; // 用被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory;
}
@Override
public void produceCloth() {
System.out.println("代理工厂做一些准备工作");
factory.produceCloth();
System.out.println("代理工厂做一些收尾工作");
}
}
// 被代理类
class NikeClothFactory implements ClothFactory {
@Override
public void produceCloth() {
System.out.println("Nike工厂生产运动服");
}
}
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
Java 动态代理相关 API:
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
创建一个动态代理类所对应的Class对象public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
用来生成动态代理类对象Object invoke(Object proxy, Method method, Object[] args) throws Throwable
,以完成代理的具体操作import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
要实现动态代理,需要解决的问题:
Q1: 如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
Q2: 当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法
*/
public class DynamicProxyDemo {
public static void main(String[] args) {
OrdinaryPeople o = new OrdinaryPeople();
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(o);
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("米饭");
System.out.println("---------------------------");
NikeClothFactory nike = new NikeClothFactory();
ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nike);
proxyClothFactory.produceCloth();
}
}
class ProxyFactory {
/**
* 返回一个代理类对象
* @param obj 被代理类的对象
* @return 代理类对象
*/
public static Object getProxyInstance(Object obj) {
// ClassLoader loader, Class<?>[] interfaces, reflect.InvocationHandler h
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader()
, obj.getClass().getInterfaces(), handler);
}
}
// 代理实例的 [调用处理程序] 实现的接口↘ 每个代理实例都具有一个关联的调用处理程序
class MyInvocationHandler implements InvocationHandler {
private Object obj; // 需要使用被代理类的对象进行赋值
public void bind(Object obj) {
this.obj = obj;
}
// 对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke()
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("被代理对象相应方法执行之前,做点啥...");
Object ret = method.invoke(obj, args);
System.out.println("被代理对象相应方法执行之后,再做点啥...");
return ret;
}
}
// 被代理类
class OrdinaryPeople implements Human {
@Override
public String getBelief() {
return "I can fly ~~~";
}
@Override
public void eat(String food) {
System.out.println("我要开动了!目标:" + food);
}
}
interface Human {
String getBelief();
void eat(String food);
}
原文:https://www.cnblogs.com/liujiaqi1101/p/13340706.html