面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?
之前我已经写过了关于动态代理的两篇文章,本来以为这块应该没啥问题,没想到今天又被难住了…
太难了!!!
之前文章的链接:
在动态代理学习(二)JDK动态代理源码分析中我已经讲JDK底层生成的字节码文件反编译成了java代码,如下:
public final class proxy extends Proxy implements MyService {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public proxy(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void test01() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void test02(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.dmz.proxy.target.MyService").getMethod("test01");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.dmz.proxy.target.MyService").getMethod("test02", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
但是这里有个问题没有很好的进行分析,就是JDK的动态代理为什么要继承Proxy这个类呢?
在之前的文章中提到过:我们可以发现代理类并没有使用Proxy中的什么属性或者方法(虽然使用了InvocationHandler对象,但是也可以在生成class之初就将InvocationHandler放入到代理类中)
这样看来,不继承这个Proxy确实也能实现动态代理。
如果要回答为什么要使用Proxy这个类,我们不妨假设所有的代理类都不继承这个类,那么会怎么样呢?
这样的话,代理类就要变成这样子
// 去 extends Proxy
public final class proxy implements MyService {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
// 这个时候代理类就需要自己持有一个InvocationHandler对象了
private InvocationHandler h;
public proxy(InvocationHandler h){
// super(var1);
this.h = h;
}
// ......
}
这样确实还是能实现代理类的所有功能,但是我们会发现,在生成每一个代理类的时候都需要往生成的字节码中写入这么一段。相比于继承的方式这种形式写入的内容要多一些,这也意味着消耗的性能要高一些。
所以基于此我们可以总结出第一个原因:
基于继承的方式可以减少生成代理类时产生的性能消耗
如果仅仅基于上面的原因没办法说服你的话,那么不要急,继续往下看,我们思考这么一种场景,如果有一天我需要对所有的代理类进行某一种处理的话,我们该如何知道这个类是一个经过代理产生的类呢?
如果是基于上面这种方式的话,我能想到的办法只有一种
- 遍历所有的类
- 判断该类中是否持有一个InvocationHandler对象
但是难道只有代理类能持有一个InvocationHandler吗?很显然不是的,我们也可以自己定义一个类,也能持有一个InvocationHandler。
但是如果通过继承Proxy的方式的话,我们只需要
- 遍历所有类
- 判断它是否是一个Proxy(instance of Prxoy)
这样就能完成我们的需求
最后我想说的是,我觉得Jdk自所以要这么进行实现,是因为它将所有的代理类进行了一层抽象,为所有的代理类定义了一个父类。所有的代理类都有一个共同点---------持有一个InvocationHandler。所以基于此,抽象出一个父类Proxy。同时又由于JDK的动态代理就是基于接口代理来设计的,继承一个父类并没有违背它设计的初衷。因此Proxy就作为所有代理类的父类诞生了!!!
本文只是个人看法,欢迎各路大神指正!
码字不易,求个赞吧!
面试官:你说你懂动态代理,那你知道为什么JDK中的代理类都要继承Proxy吗?的更多相关文章
- 8年经验面试官详解 Java 面试秘诀
作者 | 胡书敏 责编 | 刘静 出品 | CSDN(ID:CSDNnews) 本人目前在一家知名外企担任架构师,而且最近八年来,在多家外企和互联网公司担任Java技术面试官,前后累计面试了有两三 ...
- 想入职阿里的Java开发者必看,阿里巴巴面试官实战经验分享!
最近社区Java技术进阶群的小伙伴总是会问,如何面试阿里Java技术岗,需要什么条件,做哪些准备:小编就这些问题找到了阿里技术团队中在一线真正带Java开发团队并直接参与技术面试的专家,分享了自身在筛 ...
- (转)轻松学,Java 中的代理模式及动态代理
背景:讲到反射机制,肯定会想到动态代理. 轻松学,Java 中的代理模式及动态代理 代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强.值得注意的是,代理类和被代理类应该 ...
- 面试官:你连RESTful都不知道我怎么敢要你?
目录 01 前言 02 RESTful的来源 03 RESTful6大原则 1. C-S架构 2. 无状态 3.统一的接口 4.一致的数据格式 4.系统分层 5.可缓存 6.按需编码.可定制代码(可选 ...
- 当阿里面试官问我:Java创建线程有几种方式?我就知道问题没那么简单
这是最新的大厂面试系列,还原真实场景,提炼出知识点分享给大家. 点赞再看,养成习惯~ 微信搜索[武哥聊编程],关注这个 Java 菜鸟. 昨天有个小伙伴去阿里面试实习生岗位,面试官问他了一个老生常谈的 ...
- 动态代理学习(二)JDK动态代理源码分析
上篇文章我们学习了如何自己实现一个动态代理,这篇文章我们从源码角度来分析下JDK的动态代理 先看一个Demo: public class MyInvocationHandler implements ...
- 面试官:线程池如何按照core、max、queue的执行循序去执行?(内附详细解析)
前言 这是一个真实的面试题. 前几天一个朋友在群里分享了他刚刚面试候选者时问的问题:"线程池如何按照core.max.queue的执行循序去执行?". 我们都知道线程池中代码执行顺 ...
- 面试一个百度T7程序员,一道简单的题没答上来!网友却都在吐槽面试官!
程序员面试时都考些什么? 一个面试官得意洋洋地说自己面了一个百度T7,出了一道coding题,结果对方连最长上升子序列都写不出来. 楼主本想嘲弄一下百度T7的代码水平低,没想到网友们炸开了锅,纷纷 ...
- 面试官:小伙子,你给我讲一下java类加载机制和内存模型吧
类加载机制 虚拟机把描述类的数据从 Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制. 类的生命周期 加载(Loadi ...
随机推荐
- break与continue用法注意事项
break 中断循环执行,跳出循环 注意,break只能中断自己所在的循环,一般用在内层循环,但是不能中断外层循环中的代码. continue 跳到循环的下一轮继续执行,结束自己所在循环体代码,继续自 ...
- 1年左右的Java开发经验面试者的心得
面试,相信只要踏入这行业的人都会经历,不同的公司有不同的面试流程,但是综合起来,其实还是大体一致的!只有不断的总结自己的面试经历,得出自己的技术不足点,才能更好的去查缺补漏,从而更加自信的进行面试找到 ...
- WinForm:API
一.WndProc: 主要用在拦截并处理系统消息和自定义消息 比如:windows程序会产生很多消息,比如你单击鼠标,移动窗口都会产生消息.这个函数就是默认的消息处理函数.你可以重载这个函数来制定自 ...
- 字符串的常用操作和方法(Python入门教程)
字符串的常用操作 很好理解 字符串可以用 ' + ' 连接,或者乘一个常数重复输出字符串 字符串的索引操作 通过一对中括号可以找到字符串中的某个字符 可以通过正负数双向操作噢 用一个中括号来实现 为什 ...
- 【draft】Team project :Bing dictionary plug-in
课后~ 开会调研开会调研开会~ 在和Bing词典负责人进行了可行性的深入磋商后,我们对本次选题有了更加清晰的认识~困难好多~然而终于敲定了项目内容,我们的目标是这样一款神奇的插件,它帮你记录下新近查询 ...
- jmeter元件的执行顺序
元件的执行顺序 在同一作用域范围内,test plan中的元件按照以下顺序执行:1) Config Elements--配置元件2) Pre-porcessors --前置处理器3) Timer-定时 ...
- 如何使用Jsoup爬取网页内容
前言: 这是一篇迟到很久的文章了,人真的是越来越懒,前一阵用jsoup实现了一个功能,个人觉得和selenium的webdriver原理类似,所以今天正好有时间,就又来更新分享了. 实现场景: 爬取博 ...
- Mac剪切板中的PNG保存到文件swift
SwiftGG 教程大全 中文翻译 命令行工具开发教程 Line Programs on macOS Tutorial swift4,较详细 Swift基础中需要注意的点 NSPasteboard M ...
- 移动(appium)自动化测试-爬虫的另一种手段
appium自动化测试环境搭建: 1.Python环境(推荐2.7)和jdk. 2.Adb工具的下载:自己单独下载adb.夜神模拟器自带和Android sdk 3.Apk安装介质:真机.Androi ...
- 看完肯定懂的 Java 字符串常量池指南
字符串问题可谓是 Java 中经久不衰的问题,尤其是字符串常量池经常作为面试题出现.可即便是看似简单而又经常被提起的问题,还是有好多同学一知半解,看上去懂了,仔细分析起来却又发现不太明白. 背景说明 ...