Java基础--注解、反射

阅读目录

 


回到顶部

一、注解(Annotation)

1、什么是注解?

  从 JDK5 开始,Java 增加了 Annotation(注解),Annotation 是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

2、Annotation 与注释的区别:

  (1)Annotation 不是程序本身,可以对程序进行解释,此处可以理解为注释。但是 Annotation 可以被其他程序(比如编译器)读取,并进行处理。
  (2)注解与注释最大的区别就是注解存在被处理的流程,即注解是会被程序处理的。

3、注解的格式:

  (1)以 “@注释名” 的形式在代码中存在。
  (2)注解可以附加在程序元素( 包、类、构造器、方法、成员变量、参数、局域变量 )上面,为其添加额外的辅助信息,可以通过反射机制访问这些数据。
  (3)Annotation 不能运行,其只有成员变量,没有方法。Annotation 与 public、final 等修饰符地位类似,属于程序元素的一部分,但不能作为程序元素使用。

4、常见注解:

  (1)@Override
    定义在 java.lang.Override 中,此注释只用于修饰方法,表示重写一个父类的方法。

【举例:】
 @Override
 public String toString() {
     return "Hello";
}

  (2)@Deprecated

    定义在 java.land.Deprecated 中,此注释可用于修饰方法、属性、类,表示该方法、类、属性不推荐使用(废弃)。在方法、类、属性上会有一条删除线(形如toString())。

【举例:】
@Deprecated
public String toString() {
    return "TimerTaskDemo []";
}

  (3)@SuppressWarnings
    定义在 java.lang.SuppressWarnings 中,用来阻止编译时的警告信息。其使用时需要设置参数。

【参数为:】
deprecation, 使用了过时的类或方法的警告。
unchecked,执行了未检查的转换时的异常,比如集合未指定泛型。
fallthrough,当在 switch 语句发生 case 穿透时的警告。
path,当类路径、源文件路径不存在时的警告。
serial,可序列化类缺少 serialVersionUID 时的警告。
finally,任何 finally 不能完成时的警告。
all,以上所有警告。

【格式:】
@SuppressWarnings("all")
或者
@SuppressWarnings(value
= {"serial", "unchecked"})
注意:

  @SuppressWarnings("resource")

  对于 J2EE,可以使用 @Resource 来完成依赖注入或者叫资源注入,但是当你在一个类中使用已经使用注解的类,却没有为其注入依赖,代码会提示相关信息,可以使用 @SuppressWarnings("resource") 来取消提示信息。

5、元注解:

  (1)元注解的作用就是负责注解其他的注解。Java5.0 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明。存在于 java.lang.annotation 中。

  (2)元注解分类:
    @Target
    @Retention
    @Documented
    @Inherited

  (3)@Target 元注解:
    用于描述注解的使用范围。Annotation 可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数)。在 Annotation 类型的声明中使用了 target 可更加明晰其修饰的目标。

【格式:】
public @interface Target
{ElementType[] value();}

【参数:ElementType】
CONSTRUCTOR: 用于描述构造器
FIELD: 用于描述成员变量
LOCAL_VARIABLE: 用于描述局部变量
METHOD: 用于描述方法
PACKAGE: 用于描述包
PARAMETER: 用于描述参数
TYPE: 用于描述类、接口 (包括注解类型) 或 enum 声明

【举例:】
@Target({java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.FIELD, java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.PARAMETER, java.lang.annotation.ElementType.CONSTRUCTOR, java.lang.annotation.ElementType.LOCAL_VARIABLE})

  (4)@Retention 元注解:
    用于描述注解的声明周期。某些 Annotation 仅出现在源代码中,而被编译器丢弃;而另一些却被编译在 class 文件中;编译在 class 文件中的 Annotation 可能会被虚拟机忽略,而另一些在 class 被装载时将被读取(请注意并不影响 class 的执行,因为 Annotation 与 class 在使用上是被分离的)。使用这个 meta-Annotation 可以对 Annotation 的“生命周期”限制。

【格式:】
public @interface Retention
{RetentionPolicy value();
}

【参数:RetentionPoicy】
SOURCE: 在源文件中有效(即源文件保留)
CLASS: 在 class 文件中有效(即 class 保留)
RUNTIME: 在运行时有效(即运行时保留,可以通过反射机制读取)

【举例:】
@Retention(RetentionPolicy.SOURCE)

  (5)@Documented 元注解:
    用于描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因此可以被例如 javadoc 此类的工具文档化。Documented 是一个标记注解,没有成员。

  (6)@Inherited 元注解:
    @Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了 @Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该 class 的子类。
注意:
    @Inherited annotation 类型是被标注过的 class 的子类所继承。类并不从它所实现的接口继承 annotation,方法并不从它所重载的方法继承 annotation。
    当 @Inherited annotation 类型标注的 annotation 的 Retention 是 RetentionPolicy.RUNTIME,则反射 API 增强了这种继承性。如果我们使用 java.lang.reflect 去查询一个 @Inherited annotation 类型的 annotation 时,反射代码检查将展开工作:检查 class 和其父类,直到发现指定的 annotation 类型被发现,或者到达类继承结构的顶层。

 

6、自定义注解:

  (1)自定义注解时,需要使用 @interface 用来声明一个注解,其会自动继承 java.lang.annotation.Annotation 接口。

【格式:】
public @interface 注解名 {定义体}
【或者:】
public @interface 注解名 {类型 value() default 默认值;   //这里是参数,不是抽象方法。
}

其中定义体实质是声明了一个配置参数(注:此处不是抽象方法)。
1、方法名指的是参数名。
2、返回值类型指的是参数的类型(只能为基本类型、Class、String、enum、Annotation 类型、以及以上所有类型的数组)。
3、可以通过 default 来声明参数的默认值。
4、如果只有一个参数,那么参数名(方法名)一般为 value。
5、只能使用 public, default 两个权限修饰符。  

  (2)方法:

判断类或者方法是否有注解
    boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

获得注解对象
<A extends Annotation> A getAnnotation(Class<A> annotationClass) //获取指定注解
Annotation[] getAnnotations() //获取当前元素上的所有注解

【举例:】
package com.test;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldDemo {
String columnName()
default "";

String type() </span><span style="color: rgba(0, 0, 255, 1)">default</span> ""<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 0, 255, 1)">int</span> length() <span style="color: rgba(0, 0, 255, 1)">default</span> 10<span style="color: rgba(0, 0, 0, 1)">;

}

@Table("student")
class Student {
@FieldDemo(columnName
= "id", length = 10, type = "int")
private int id;

@FieldDemo(columnName </span>= "name", length = 20, type = "varchar"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String name;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setName(String name) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}

}

public class AnnotationDemo {
public static void main(String[] args) {
try {
// 获取 Student 类的信息
Class classDemo = Class.forName("com.test.Student");
// Class<Student> classDemo = (Class<Student>)Class.forName("com.test.Student");
System.out.println(classDemo); // 输出 class com.test.Student

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取当前元素上的所有注解,此时获取的是@Table</span>
        Annotation[] annotations =<span style="color: rgba(0, 0, 0, 1)"> classDemo.getAnnotations();
        </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (Annotation annotation : annotations) {
            System.out.println(annotation);
        } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出@com.test.Table(value=student)

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 直接获取指定的某注解</span>
        Table table = (Table) classDemo.getAnnotation(Table.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        System.out.println(table.value()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出student

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取类的属性的注解</span>
        Field field = classDemo.getDeclaredField("name"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取指定注解</span>
        FieldDemo fieldDemo = field.getAnnotation(FieldDemo.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出name varchar 20</span>
        System.out.println(fieldDemo.columnName() + " " + fieldDemo.type() + " " +<span style="color: rgba(0, 0, 0, 1)"> fieldDemo.length());
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        e.printStackTrace();
    }
}

}

 

回到顶部

二、反射机制

1、什么是反射?

  JAVA 反射机制指的是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;即这种动态获取信息以及动态调用对象方法的功能称为 java 语言的反射机制。
  JAVA 中与反射相关的类,放在 java.lang.reflect 包中。

2、Class 类

  Class 对象包含了一个类的完整的结构信息。通过 Class 对象,可以对类进行操作,即为反射。
  (1)规则:
    Class 类拥有泛型作为定义。
    Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
    Class 类没有 public 构造方法。
    Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
    一个类只有一个 Class 对象。

  (2)内置 class 实例(class 对象):

byte.classshort.classint.classlong.classchar.classfloat.classdouble.classboolean.classvoid.class.
注:
int.class != Integer.classint.class == Integer.Type  。

  (3)对于数组类型 class 实例:
    每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

int[] a = new int[100];
int[] b = new int[10];
long[] c = new long[10];
int[][] d = new int[10][2];
System.out.println(a.getClass());//输出 class [I
System.out.println(b.getClass());//输出 class [I
System.out.println(c.getClass());//输出 class [J
System.out.println(d.getClass());//输出 class [[I
System.out.println(a.getClass() == b.getClass());//输出 true

  (4)获取 Class 实例的方法:

【方法 1:】
根据传入的参数动态装载一个类,并且做类的初始化。
    Class.forName() 方法

【方法 2:】
获得对象运行时所指的真正对象(多态的场合返回子类的类名)。
Class.getClass() 方法

【方法 3:】
JVM 将使用类 A 的类装载器,将类 A 装入内存 (前提是: 类 A 还没有装入内存),不对类 A 做类的初始化工作. 返回类 A 的 Class 的对象。
A.class 属性

  (5)通过 Class 实例创建对象:

Class.newInstance() 方法 。调用默认构造函数,获得一个实例

Class.newInstance 方法与 new 的区别
newInstance: 弱类型。低效率。只能调用无参构造。
new:强类型。相对高效。能调用任何 public 构造。

  (6)常用方法:

【获得构造器:】
Constructor<T> getDeclaredConstructor(Class<?>...)  获得指定构造方法
Constructor<?>[] getDeclaredConstructors()    获得所有构造方法(声明顺序)
Constructor<T> getConstructor(Class<?>...)    获得权限为 public 的指定构造方法
Constructor<?>[] getConstructors()    获得权限为 public 的所有构造方法

【获得普通方法(成员方法):】
Method[] getDeclaredMethods() 获得该类中定义的所有方法 (不包含父类继承)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)根据该类中定义的指定方法 ( 不包含父类继承)
Method[] getMethods() 获得权限为 public 的所有的方法 (包含父类继承)
Method getMethod(String name, Class
<?>... parameterTypes)获得权限为 public 的指定的方法 ( 包含父类继承)

【获得属性(成员变量):】
Field[] getDeclaredFields() 获得该类中定义的所有属性(不包含继承)
Field getDeclaredField(String name) 获得该类中定义的指定属性 (不包含继承)
Field[] getFields() 获得该类中所有 public 的属性 (包含继承)
Field getField (String name) 获得该类中指定的 public 属性 (包含继承)

【获得内部类:】
Class<?>[] getDeclaredClasses() 获得所有内部类 (不包含继承)
Class
<?>[] getClasses() 获得所有权限为 public 的内部类(包含继承)

【其他:】
Package getPackage() 获得 Package 对象
String getName() 获得类的全称,即包名 +类名
String getSimpleName() 获得类的简称,即类名
Class
<? super T> getSuperclass() 获得继承的类
Class
<?>[] getInterfaces() 获得实现的接口

  (7)获得构造器后,可以进行的操作

  (8)获得成员方法后,可以进行的操作

  (9)获得成员变量后,可以进行的操作

package com.test;

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

class Teacher {
private String name;
private int age;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Teacher() {
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> Teacher(String name, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setName(String name) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getAge() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> age;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setAge(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
}

}

public class ReflectionDemo {
public static void main(String[] args) {
try {
// 加载 Teacher.class 对象
Class<Teacher> teacherClass = (Class<Teacher>) Class.forName("com.test.Teacher");

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取无参构造器,若Teacher类没有无参构造方法,则会报错</span>
        Teacher teacher =<span style="color: rgba(0, 0, 0, 1)"> teacherClass.newInstance();
        System.out.println(teacher </span>+ ", " + teacher.getName() + ", " +<span style="color: rgba(0, 0, 0, 1)"> teacher.getAge());

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取有参构造器</span>
        Constructor&lt;Teacher&gt; constructor = teacherClass.getDeclaredConstructor(String.<span style="color: rgba(0, 0, 255, 1)">class</span>, <span style="color: rgba(0, 0, 255, 1)">int</span>.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        Teacher teacher2 </span>= constructor.newInstance("tom", 20<span style="color: rgba(0, 0, 0, 1)">);
        System.out.println(teacher2 </span>+ ", " + teacher2.getName() + ", " +<span style="color: rgba(0, 0, 0, 1)"> teacher2.getAge());

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取成员方法</span>
        Teacher teacher3 =<span style="color: rgba(0, 0, 0, 1)"> teacherClass.newInstance();
        Method method </span>= teacherClass.getDeclaredMethod("setAge", <span style="color: rgba(0, 0, 255, 1)">int</span>.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        method.invoke(teacher3, </span>30<span style="color: rgba(0, 0, 0, 1)">);
        System.out.println(teacher3.getAge());

        Method method2 </span>= teacherClass.getDeclaredMethod("getAge"<span style="color: rgba(0, 0, 0, 1)">);
        System.out.println(method2.invoke(teacher3));

        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获取成员变量</span>
        Teacher teacher4 =<span style="color: rgba(0, 0, 0, 1)"> teacherClass.newInstance();
        Field field </span>= teacherClass.getDeclaredField("age"<span style="color: rgba(0, 0, 0, 1)">);
        field.setAccessible(</span><span style="color: rgba(0, 0, 255, 1)">true</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 忽略安全检查,可以获取private类型的数据,破坏封装性。</span>

System.out.println(field.get(teacher4));
}
catch (Exception e) {
e.printStackTrace();
}
}
}

【结果:】
com.test.Teacher@2a139a55, null, 0
com.test.Teacher@15db9742, tom,
20
30
30
0

3、反射机制性能问题

  setAccessible,是启用和禁用安全检查的开关,其值为 true 时,表示禁用 Java 语言访问的安全性检查,为 false 时,表示启用安全性检查,将其值设为 true,可以提高反射的效率。

 

回到顶部

三、静态代理与动态代理

1、静态代理

(1)静态代理其实就是指设计模式中的代理模式。代理模式为其他对象提供一种代理以控制对这个对象的访问。代理类只能为一个接口服务,使用静态代理会产生很多代理类。
(2)UML 图:

 

(3)代码演示:

【Subject.java】
package construction.pattern.proxy;

/**

  • 定义一个代理类与被代理类的公共接口,使得被代理类出现的地方,代理类均能出现
    */
    interface Subject {
    public abstract void request();
    }

【RealSubject.java】
package construction.pattern.proxy;

/**

  • 被代理类。定义 代理类 所代表的真实实体。

*/
public class RealSubject implements Subject {

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> request() {
    System.out.println(</span>"这是真实请求"<span style="color: rgba(0, 0, 0, 1)">);
}

}

【RealSubjectProxy.java】
package construction.pattern.proxy;

/**

  • 代理类,用于控制被代理类。保存一个被代理类的引用使得代理可以访问实体。

*/
public class RealSubjectProxy implements Subject {
private RealSubject realSubject;//保存一个被代理类的引用

@Override
public void request() {
System.out.println(
"代理开始......");
if (realSubject == null) {
realSubject
= new RealSubject();
}
realSubject.request();
System.out.println(
"代理结束......");
}
}

【ProxyDemo.java】
package construction.pattern.proxy;

/**

  • 静态代理的小 demo。
  • 被代理类能出现的地方,代理类均能出现。
    */
    public class ProxyDemo {
    public static void main(String[] args) {
    Subject subject
    = new RealSubjectProxy();
    subject.request();
    }
    }

【执行结果:】
代理开始......
这是真实请求
代理结束......

(4)代码分析:
静态代理模式固然在访问无法访问的资源,增强现有的接口业务功能方面有很大的优点,但是大量使用这种静态代理,会使我们系统内的类的规模增大,并且不易维护;并且由于 Proxy 和 RealSubject 的功能本质上是相同的,Proxy 只是起到了中介的作用,这种代理在系统中的存在,导致系统结构比较臃肿和松散。

2、动态代理

(1)为了解决静态代理的问题,动态代理的想法就被提出。即在运行状态下,在需要被代理的地方,根据 Subject 和 RealSubject,动态地创建一个 Proxy,用完之后,就会销毁,可以避免类臃肿。

  即动态代理指的是 在程序运行时动态的创建目标类的代理类的对象,且通过代理对象来调用目标对象。

(2)Java 动态代理基于经典代理模式,引入了一个 InvocationHandler,InvocationHandler 负责统一管理所有的方法调用。

/**
  * 参数
  *  proxy - 代理的真实对象。
  *  method - 所要调用真实对象的某个方法的 Method 对象 
  *  args - 所要调用真实对象某个方法时接受的参数
  */
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
}

(3)动态代理步骤:
  step1:获取 RealSubject 上的所有接口列表;
  step2:确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX;
  step3:根据需要实现的接口信息,在代码中动态创建 该 Proxy 类的字节码;
  step4:将对应的字节码转换为对应的 class 对象;
  step5:创建 InvocationHandler 实例 handler,用来处理 Proxy 所有方法调用;
  step6:Proxy 的 class 对象 以创建的 handler 对象为参数,实例化一个 proxy 对象。

【Proxy 常用的方法】
/**
 * loader - 一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载。
 * interfaces - 一个 Interface 对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口 (多态),这样我就能调用这组接口中的方法了
 * h - 一个 InvocationHandler 对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler 对象上
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

(4)UML 图:

(5)代码实现:

【Subject.java】
package construction.pattern.proxy.dynamicProxy;

/**

  • 定义一个代理类与被代理类的公共接口,使得被代理类出现的地方,代理类均能出现
    */
    interface Subject {
    void hello();

    String bye();
    }

【RealSubject.java】
package construction.pattern.proxy.dynamicProxy;

/**

  • 被代理类。定义 代理类 所代表的真实实体。

*/
public class RealSubject implements Subject {

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> hello() {
    System.out.println(</span>"Hello World"<span style="color: rgba(0, 0, 0, 1)">);
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String bye() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> "GoogBye"<span style="color: rgba(0, 0, 0, 1)">;
}

}

【DynamicProxy.java】
package construction.pattern.proxy.dynamicProxy;

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

/**

  • 动态代理类。 每一个动态代理类都必须要实现 InvocationHandler 这个接口,并且每个代理类的实例都关联到了一个
  • Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler 这个接口的 invoke
  • 方法来进行调用。

*/
public class DynamicProxy implements InvocationHandler {

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用于保存被代理对象(真实对象)</span>
<span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Object subject;

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 构造方法,给被代理对象赋初值
 * 
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> subject
 *            真实对象
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> DynamicProxy(Object subject) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.subject =<span style="color: rgba(0, 0, 0, 1)"> subject;
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 参数: 
 *  proxy - 代理的真实对象(一般在代码中不使用)。 
 *  method - 所要调用真实对象的某个方法的 Method 对象 
 *  args - 所要调用真实对象某个方法时接受的参数
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> Object invoke(Object proxy, Method method, Object[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Throwable {
    System.out.println(</span>"可以在代理前,进行一些操作..."<span style="color: rgba(0, 0, 0, 1)">);
    System.out.println(</span>"Before proxy......"<span style="color: rgba(0, 0, 0, 1)">);
    System.out.println();

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用</span>
    System.out.println("当前调用的方法为:" +<span style="color: rgba(0, 0, 0, 1)"> method);
    Object object </span>= method.invoke(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.subject, args);
    System.out.println();

    System.out.println(</span>"可以在代理后,进行一些操作..."<span style="color: rgba(0, 0, 0, 1)">);
    System.out.println(</span>"After proxy......"<span style="color: rgba(0, 0, 0, 1)">);
    System.out.println();
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> object;
}

}

【DynamicProxyDemo.java】
package construction.pattern.proxy.dynamicProxy;

import java.lang.reflect.Proxy;

/**

  • 演示动态代理的小 Demo

*/
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建一个被代理的对象(真实对象)
Subject realSubject = new RealSubject();
// 输出真实对象的类名
System.out.println(realSubject.getClass().getName());

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 将真实对象传入 InvocationHandler 中,即DynamicProxy中</span>
    DynamicProxy proxy = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DynamicProxy(realSubject);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过Proxy类的 newProxyInstance 方法来创建一个代理对象
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 第一个参数, proxy.getClass().getClassLoader(), 使用proxy这个类的ClassLoader对象来加载我们的代理对象
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 第二个参数, subject.getClass().getInterfaces(), 获取真实对象的所有接口,从而使代理对象能调用被代理对象的方法
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 第三个参数, proxy, 关联 InvocationHandler 对象</span>
    Subject subject =<span style="color: rgba(0, 0, 0, 1)"> (Subject) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), proxy);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出代理对象的类名</span>

System.out.println(subject.getClass().getName());
subject.hello();
//会自动触发代理类的 invoke 方法,
System.out.println(subject.bye());
}
}

【结果:】
construction.pattern.proxy.dynamicProxy.RealSubject
construction.pattern.proxy.dynamicProxy.$Proxy0
可以在代理前,进行一些操作...
Before proxy......

当前调用的方法为:public abstract void construction.pattern.proxy.dynamicProxy.Subject.hello()
Hello World

可以在代理后,进行一些操作...
After proxy......

可以在代理前,进行一些操作...
Before proxy......

当前调用的方法为:public abstract java.lang.String construction.pattern.proxy.dynamicProxy.Subject.bye()

可以在代理后,进行一些操作...
After proxy......

GoogBye