Java代理类Proxy的用法
代理(proxy)
利用代理可以在运行时创建一个实现了一组给定接口的新类。这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。
何时使用代理
假设有一个表示接口的Class对象(有可能只包含一个接口),它的确切类型在编译时无法知道。要想构造一个实现这些接口的类,就需要使用newInstance方法或反射找出这个类的构造器。但是,不能实例化一个接口,需要在程序处于运行状态时定义一个新类。
代理类可以在运行时创建全新的类。这样的代理类能够实现指定的接口。尤其是,它具有下列方法:
- 指定接口所需要的全部方法
- Object类中的全部方法,例如, toString, equals等。
创建代理对象
要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这个方法有三个参数:
- 一个类加载器(class loader)。
- 一个Class对象数组,每个元素都是需要实现的接口。
- 一个调用处理器
还有两个需要解决的问题。如何定义一个处理器?能够用结果代理对象做些什么?当然,这两个问题的答案取决于打算使用代理机制解决什么问题。比如
- 路由对远程服务器的方法调用
- 调试,跟踪
- log
Demo
我们定义一个处理器,用来打印调用的参数
public class TraceHandler implements InvocationHandler {
private Object target;
public TraceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print(target);
System.out.print("." + method.getName() + "(");
if (args != null) {
for (int i = 0; i < args.length; i++) {
System.out.print(args[i]);
if (i<args.length - 1){
System.out.print(", ");
}
}
}
System.out.println(")");
return method.invoke(target, args);
}
}
接下来,我们用它来代理Comparable接口,看看怎么调用。比如Arrays的二分查找方法binarySearch
@Test
public void traceBinarySearch() {
Object[] elements = new Object[1000];
for (int i = 0; i < elements.length; i++) {
Integer value = i + 1;
InvocationHandler handler = new TraceHandler(value);
Object proxy = Proxy.newProxyInstance(null, new Class[]{Comparable.class}, handler);
elements[i] = proxy;
}
Integer key = new Random().nextInt(elements.length) + 1;
int result = Arrays.binarySearch(elements, key);
if (result > 0) {
System.out.println(elements[result]);
}
}
控制台打印结果:
500.compareTo(94)
250.compareTo(94)
125.compareTo(94)
62.compareTo(94)
93.compareTo(94)
109.compareTo(94)
101.compareTo(94)
97.compareTo(94)
95.compareTo(94)
94.compareTo(94)
94.toString()
94
代理类的特性
- 代理类是在运行过程中创建的,创建完毕后和常规类相同,虚拟机同等对待。
- 所有的代理类都扩展于Proxy类。一个代理类只有一个实例域---调用处理器,它定义在Proxy的超类中。
- 没有定义代理类的名字,Sun虚拟机中的Proxy类将生成一个以字符串$Proxy开头的类名。
- 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。也就是说,如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,只能得到同一个类的两个对象。比如
class com.sun.proxy.$Proxy4
.可以使用getProxyClass
来获取这个类。 - 代理类一定是public final的。
- 可以通过
Proxy.isProxyClass
方法检测一个特定的Class对象是否代表一个代理类。
来源
- Java核心技术
Java代理类Proxy的用法的更多相关文章
- Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理
面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问"茴香豆的茴字有哪几种写法?" 所谓代理模式,是指客户端(Cl ...
- Java代理设计模式(Proxy)的几种具体实现
Proxy是一种结构设计模型,主要解决对象直接访问带来的问题,代理又分为静态代理和动态代理(JDK代理.CGLIB代理. 静态代理:又程序创建的代理类,或者特定的工具类,在平时开发中经常用到这种代理模 ...
- 深入解析OpenCart的代理类proxy
1.什么是代理类 代理类指的是连接远程对象或不可见对象的接口,通常被客户端调用来连接真实的服务对象.更准确的定义参见维基百科 2.代理的作用 作为一个包装类,提供额外的功能 延迟加载 在本文讲到的op ...
- java枚举类的常见用法
枚举类型(Enumerated Type) 很早就出现在编程语言中,它被用来将一组类似的值包含到一种类型当中.而这种枚举类型的名称则会被定义成独一无二的类型描述符,在这一点上和常量的定义相似.不过相比 ...
- java代理类及AOP
1.代理架构图 2.AOP 3.动态代理概念 4.动态代理工作原理图
- Java中的动态代理以及Proxy类的偷瞄
动态代理机制 所谓动态代理,即通过代理类Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. Java动态代理类位于Java.lang.reflect包 ...
- Java的动态代理(dynamic proxy)
什么是动态代理(dynamic proxy) 动态代理(以下称代理),利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类(也称“动态代理类”)及其实例(对 ...
- 探索Mybatis之JDK动态代理:探究Proxy.newProxyInstance()生成的代理类解析
Mybatis的Mapper接口UserMapper 1 package com.safin.Mapper; 2 3 import com.safin.Pojo.User; 4 5 import ja ...
- java代理通俗简单解析
1 代理 1.1 代理的概念和作用 代理的概念很好理解,就像黄牛代替票务公司给你提供票,经纪人代理艺人和别人谈合作.Java的代理是指实现类作为代理类的属性对象, ...
随机推荐
- CentOS 7 firewalld详解,添加删除策略
一.CentOS7中firewall防火墙 修改防火墙配置文件之前,需要对之前防火墙[/etc/firewalld/zones/public.xml]做好备份 重启防火墙后,需要确认防火墙状态和防火墙 ...
- 【转】linux下使用sqlplus执行包含语句块的sql文件,运行时会不断显示行号,而在plsqldev中能执行
一.数据库:Oracle数据库 二.sql文件内容: --创建函数 CREATE OR REPLACE function fun_createuid1 return varchar2 is Resul ...
- 【Java线程与内存分析工具】VisualVM与MAT简明教程
目录 前言 VisualVM 安装与配置 本地使用 远程监控 MAT 使用场景 安装与配置 获得堆转储文件 分析堆转储文件 窥探对象内存值 堆转储文件对比分析 总结 前言 本文将简要介绍Java线程与 ...
- node.js箭头函数使用
ES6允许使用=>定义函数,箭头函数使得表达更加简洁,例如 // 正常函数写法 [1,2,3].map(function (x) { return x * x; }); // 箭头函数写法 [1 ...
- make 命令与 Makefile
make 是一个工具程序,通过读取 Makefile 文件,实现自动化软件构建.虽然现代软件开发中,集成开发环境已经取代了 make,但在 Unix 环境中,make 仍然被广泛用来协助软件开发.ma ...
- 2018-8-10-win10-uwp-关联文件
原文:2018-8-10-win10-uwp-关联文件 title author date CreateTime categories win10 uwp 关联文件 lindexi 2018-08-1 ...
- C#用Call代替CallVirt之后的测试用例
一. C# 原始代码和直接结果 测试 C# 代码: class Program { static void Main(string[] args) { A c1 = new C(); c1.Foo() ...
- java基础(17):包装类、System、Math、Arrays、大数据运算
1. 基本类型包装类 大家回想下,在第三篇文章中我们学习Java中的基本数据类型时,说Java中有8种基本的数据类型,可是这些数据是基本数据,想对其进行复杂操作,变的很难.怎么办呢? 1.1 基本类型 ...
- Python当中的array数组对象
计算机为数组分配一段连续的内存,从而支持对数组随机访问:由于项的地址在编号上是连续的,数组某一项的地址可以通过将两个值相加得出,即将数组的基本地址和项的偏移地址相加.数组的基本地址就是数组的第一项的机 ...
- [b0037] python 归纳 (二二)_多进程数据共享和同步_管道Pipe
# -*- coding: utf-8 -*- """ 多进程数据共享 管道Pipe 逻辑: 2个进程,各自发送数据到管道,对方从管道中取到数据 总结: 1.只适合两个进 ...