欢迎关注同名公众号《Java鱼仔》,更多知识点你值得拥有

开场

一位穿着蓝色衬衫,牛仔裤,拿着一个白色保温杯的中年男子急匆匆地坐在你对面,看样子是项目上的东西很急,估摸面试时间不会太长,这样一想心情放松了许多......(后来我就被打脸了)

面试开始

面试官:小伙子,我看你的简历上说精通java基础对吧,那我先简单来问几个java基础。

好的好的,面试官你问。(一听到简单两个字就内心窃喜......)

面试官:你知道Java中有个东西叫代理吗?

知道知道,代理就是通过代理对象去访问实际的目标对象,比如我们在生活中租房,可以直接找房东,也可以通过某些租房平台去租房,通过租房平台的这种方式就是代理。在java中这种租房平台就被叫做代理类,代理类不仅能实现目标对象,还能增加一些额外的功能。据我所知java中的代理方式有静态代理和动态代理。(这个时候面试官很大概率会问你这两种代理模式)。

面试官:没想到你还能通过生活中的现象去理解代码,不错不错,我看你提到了静态代理和动态代理,那你给我说说什么是静态代理吧

(果然问了,还好我做了准备)静态代理就是在代码运行之前,这个代理类就已经存在了。还是以上面的租房为例,在代码中会首先创建一个通用的租房接口:

public interface Room {void rent();
}

然后需要有一个被代理的类(或者称为真实的类)和一个代理类:

public class RealRoom implements Room {private String roomname;public RealRoom(String roomname) {this.roomname = roomname;}public void rent() {System.out.println("租了"+roomname);}
}

代理类如下:

public class ProxyClass implements Room {RealRoom realRoom;public ProxyClass(RealRoom realRoom) {this.realRoom = realRoom;}public void rent() {System.out.println("租房前收取中介费");realRoom.rent();System.out.println("租房后收取服务费");}
}

代理类可以在不改变被代理对象的情况下增加功能,最后我们测试一下这个静态代理:

public class Main {public static void main(String[] args) {RealRoom realRoom =new RealRoom("碧桂园");ProxyClass proxyClass=new ProxyClass(realRoom);proxyClass.rent();}
}

然后观察结果:

租房前收取中介费
租了碧桂园
租房后收取服务费

面试官:既然静态代理那么强大,那他有什么缺点吗?

由于静态代理在代码运行之前就已经存在代理类,因此对于每一个代理对象都需要建一个代理类去代理,当需要代理的对象很多时就需要创建很多的代理类,严重降低程序的可维护性。用动态代理就可以解决这个问题。

面试官:那你给我讲一讲动态代理吧

动态代理是指代理类不是写在代码中,而是在运行过程中产生的,java提供了两种实现动态代理的方式,分别是基于Jdk的动态代理和基于Cglib的动态代理。

面试官:基于JDK的动态代理我忘了,你给我复习复习。

(我???算了算了) 实现Jdk的动态代理需要实现InvocationHandler接口,然后实现其中的invoke方法。如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类invoke,由它实现处理内容。

public class ProxyHandler implements InvocationHandler {Object object;public ProxyHandler(Object object) {this.object = object;}//proxy 代理对象//method 要实现的方法//args 方法的参数    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理执行之前:"+method.getName());Object invoke = method.invoke(object, args);System.out.println("代理执行之后:"+method.getName());return invoke;}
}

接下来在main方法中执行动态代理

public static void main(String[] args) {Room room=new RealRoom("碧桂园");//obj.getClass().getClassLoader()类加载器//obj.getClass().getInterfaces() 目标类实现的接口//InvocationHandler对象InvocationHandler invocationHandler=new ProxyHandler(room);Room proxyRoom = (Room) Proxy.newProxyInstance(room.getClass().getClassLoader(), room.getClass().getInterfaces(), invocationHandler);proxyRoom.rent();
}

这段代码的核心是Proxy.newProxyInstance,目的是运行期间生成代理类,最后通过代理类执行被代理的方法。最后结果如下:

代理执行之前:rent
租了碧桂园
代理执行之后:rent

面试官:被你这么一说我想起来动态代理了,那他的优势呢?

之前我讲静态代理的时候说静态代理的缺点在于对于每一个被代理的对象,都需要建一个代理类。因为静态代理是在项目运行前就写好的。但是动态代理就不是这样,由于动态代理在运行时才创建代理类,因此只需要写一个动态代理类就好。比如我再创建一个被代理的对象卖房:

写一个通用接口Sell

public interface Sell {void sellRoom();
}

接着还是写一个被代理对象的类:

public class RealSell implements Sell {public void sellRoom() {System.out.println("卖房了");}
}

接下来在main方法中执行动态代理

    public static void main(String[] args) {Sell sell=new RealSell();InvocationHandler invocationHandler=new ProxyHandler(sell);Sell proxysell= (Sell) Proxy.newProxyInstance(sell.getClass().getClassLoader(),sell.getClass().getInterfaces(),invocationHandler);proxysell.sellRoom();}

最终实现结果如下:

代理执行之前:sellRoom
卖房了
代理执行之后:sellRoom

通过动态代理,我可以通过一个动态代理类,去代理多个对象。

面试官:如果我记的没错,通过这种方式只能代理接口吧,我看你上面的例子也都是代理接口,那我如果想代理类该怎么办呢?

jdk动态代理确实只能代理接口,JDK动态代理是基于接口的方式,换句话来说就是代理类和目标类都实现同一个接口。如果想要代理类的话可以使用CGLib,CGLib动态代理是代理类去继承目标类,然后实现目标类的方法。

创建一个目标类CGRoom

public class CGRoom {public void rent(String roomName){System.out.println("租了"+roomName);}
}

创建cglib的动态代理类,继承MethodInterceptor ,实现其中的intercept方法

public class MyMethodInterceptor implements MethodInterceptor {public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("代理执行之前:"+method.getName());Object object=methodProxy.invokeSuper(o,objects);System.out.println("代理执行之后:"+method.getName());return object;}
}

最后通过enhance对象来创建代理类

public static void main(String[] args) {//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数Enhancer enhancer=new Enhancer();//设置目标类的字节码文件enhancer.setSuperclass(CGRoom.class);//设置回调函数enhancer.setCallback(new MyMethodInterceptor());//创建代理对象CGRoom proxy= (CGRoom) enhancer.create();proxy.rent("碧桂园");
}

最终实现以下结果:

代理执行之前:rent
租了碧桂园
代理执行之后:rent

面试官:既然动态代理被你说的这么牛,那你平常工作中有使用到吗?

平常我的业务代码中虽然几乎没有使用过动态代理,但是我工作中使用的Spring系列框架中的AOP,以及RPC框架中都用到了动态代理,以AOP为例,AOP通过动态代理对目标对象进行了增强,比如我们最常用的前置通知、后置通知等。

面试官:不错!下面再考你几个基础,说说你对注解的理解,注解又解决了哪些问题?

Java语言中的类、方法、变量、参数和包都可以用注解标记,程序运行过程中我们可以获取到相应的注解以及注解中定义的内容,比如说 Spring 中如果检测到说你的类被 @Component注解标记的话,Spring 容器在启动的时候就会把这个类归为自己管理,这样你就可以通过 @Autowired注解注入这个对象了。

面试官:那你知道如何自己去定义注解吗?

知道知道,自定义注解主要有以下四步:

第一步通过@interface声明注解:

public @interface Myannotation {String key() default "";
}

第二步通过四种元注解修饰注解:(面试的时候说出这四种注解就可以了)

元注解的作用就是负责其他注解,java中一共有四个元注解,分别是@Target,@Retention,@Documented,@Inherited,下面先介绍以下四种注解的作用:

@Target:Target说明了注解所修饰的对象范围,取值(ElementType)有:

  1. 用于描述构造器
  1. 用于描述属性
  2. 用于描述局部变量
  1. 用于描述方法
  2. 用于描述包
  3. 用于描述参数
  4. 用于描述类、接口(包括注解类型)或者enum声明

@Retention:Retention定义了注解的保留范围,取值(RetentionPoicy)有:

  1. 在源文件中有效(即源文件保留)
  1. 在class文件中有效(即class保留)
  2. 在运行时有效(即运行时保留)

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

@Inherited:Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Myannotation {String key() default "";
}

第三步使用注解,因为定义Target时定义了MEHTOD和FIELD,因此可以在属性和方法中使用这个注解:

public class MyannotationTest {@Myannotation(key = "javayz")private String username;
}

第四步利用反射解析注解

public static void main(String[] args) {Class myclass=MyannotationTest.class;Field[] fields = myclass.getDeclaredFields();for (Field field :fields){if (field.isAnnotationPresent(Myannotation.class)){System.out.println("配置了自定义注解");Myannotation annotation = field.getAnnotation(Myannotation.class);System.out.println("属性:"+field.getName()+"上的注解key为"+annotation.key());}}
}

输出结果:

配置了自定义注解
属性:username上的注解key为javayz

面试官:我看你上面第四步提到了反射是吧?那你给我讲讲什么是反射,它有啥特点:

(我晕,我就说了反射两个字啊,还好有准备)JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

在上面第四步利用反射解析注解中,我通过MyannotationTest.class获取到了MyannotationTest的类对象,又用myclass.getDeclaredFields();获取到了所有的属性。这就是反射。

结束

面试官:不错,这几块的基础算你过关了,下面我要开始真正的技术面试了!

天呐!竟然这才算开始,还好我关注了公众号《Java鱼仔》,每天在地铁公交上都能学到知识点!

面试官问我:什么是静态代理?什么是动态代理?注解、反射你会吗?相关推荐

  1. 面试官问:代理模式和装饰者模式有啥区别

    今天面试聊到了模式. 面试官问:装饰者模式了解吗,讲一下? 我:blabla... 面试官:那代理模式呢? 我:blabla.....(说完感觉怎么都一样呢) 果然,面试官又问了:那两者有什么区别呢? ...

  2. java执行sql文件_面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

    初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...

  3. 大叔手记(10):别再让面试官问你单例

    大叔手记(10):别再让面试官问你单例(暨6种实现方式让你堵住面试官的嘴) ... 2012-2-19 09:03| 发布者: benben| 查看: 283| 评论: 0 摘要: 引子经常从Recr ...

  4. 面试官问:JS的继承

    原文作者若川,掘金链接:https://juejin.im/post/5c433e216fb9a049c15f841b 写于2019年2月20日,现在发到公众号声明原创,之前被<前端大全> ...

  5. 面试官问:如果MySQL引起CPU消耗过大,你会怎么优化

    转载自  面试官问:如果MySQL引起CPU消耗过大,你会怎么优化 谁在消耗cpu? 用户+系统+IO等待+软硬中断+空闲 祸首是谁? 用户 用户空间CPU消耗,各种逻辑运算 正在进行大量tps 函数 ...

  6. 面试官问:在读多写少的情况下,如何优化 MySQL 的数据查询方案

    作者 | 面试官问     责编 | 张文 来源 | 面试官问(ID:interviewer_asked) 面试官问:假设你负责的某业务在双十一期间要搞运营活动,公司投入了大量的营销费用进行推广,此举 ...

  7. 【059期】面试官问:序列化是什么,为什么要序列化,如何实现?

    >>号外:关注"Java精选"公众号,回复"面试资料",免费领取资料!"Java精选面试题"小程序,3000+ 道面试题在线刷, ...

  8. 【154期】面试官问:请你说说 B 树、B+ 树的原理及区别?

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方留言必回,有问必答! 每天 08:35 更新文章,每天进步一点点... 之前在 ...

  9. 当面试官问Webpack的时候他想知道什么

    希沃ENOW大前端 公司官网:CVTE(广州视源股份) 前言 在前端工程化日趋复杂的今天,模块打包工具在我们的开发中起到了越来越重要的作用,其中webpack就是最热门的打包工具之一. 说到webpa ...

  10. 已经成功拿到了几个offer的我来告诉你,Android面试官问的一些问题,看完这一篇就没有拿不到的offer

    前言 我是2020年毕业于中南大学的计算机学院的,大家可以叫我小吴,我嘞毕业之后在华为实习了差不多一年多,一直都从事着Android开发. 然后2021年的时候因为我自己的一些原因打算离职到外面看看, ...

最新文章

  1. java备忘录模式应用场景_图解Java设计模式之备忘录模式
  2. Extjs4中up()和down()的用法以及组件查找_ComponentQuery类
  3. .NET Core 如何调试 CPU 爆高?
  4. Codeforces Round #246 (Div. 2) D. Prefixes and Suffixes kmp + dp
  5. WinCE内核裁减(中文字体)及字库和内核的分离
  6. 大数据学习(0)-大数据知识框图
  7. Inheritance vs. Composition in Java
  8. mdstyle暂存备用
  9. 数据--第27课 - 初始斗转
  10. 实时消息传输协议(RTMP)详解
  11. 计算机 标量,标量关系
  12. BR8041A02串口烧录PC工具操作说明(BR8041_USB_Programer_V2.0.exe)
  13. 极坐标t1t2几何意义_关于极坐标
  14. 12C Sharding 学习安装
  15. Bootstrap+web+Idea实现登录页面(含验证码)
  16. 【Java】- Incompatible types. Found: java. lang. String', required:' byte, char, short or int'
  17. 浅析GIS行业地图绘制基本要求
  18. 优化器(Optimizer)(一)
  19. 04-MongoDB集群和安全
  20. 《浮世绘---湖北人,你到底患了什么病》(转载)

热门文章

  1. webpack4打包js
  2. 什么是系统漏洞,如何处理?
  3. (42.1)【操作系统漏洞发现专题】操作系统漏洞之简介、分类、危害、发现工具、利用
  4. matlab分析地形,Matlab画地形图.doc
  5. 2020CVPR对抗样本相关论文整理(无开源代码)
  6. VS2019 项目模板制作
  7. pcdmis怎么导出模型_3D游戏模型提取、导入、导出教程
  8. 高质量前端:Code Review 很慢,你要忍一下。
  9. 电气器件系列二十二:调速电机
  10. 安排,2020新kafka视频教程零基础到精通