【Java基础】易错面试题2【反射和动态代理】(更新中..)

1、说一下Java中反射的概念和它的优缺点:

反射指的是在运行时能够分析类的能力的程序,首先说到反射我们需要知道在正常情况下,如果使用一个类,必须要经过一下几个步骤:

  • 使用important导入类所在的包。

  • 通过关键字new进行类对象实例化

  • 产生对象可以使用“对象.属性” 来进行类中属性的调用

  • 通过“对象.方法()”调用类中的方法

在反射中,使用一个类并不需要导入类所在的包,只要知道类的完整的路径就可以知道该类中的信息。反射并不需要有明确的类型对象,所有的对象使用Objiect表示。可以直接通过Object的与反射机制的混合调用类中的方法。简单来说,反射机制时程序在运行时能狗获取自身的信息。

在Java中,只要给定类的名字就可以通过反射机制来获取类的所有信息。

      1. 为什么要使用反射,它在实际编程中有什么应用

    • 静态 编译: 在编译时确定类型,绑定对象即通过。

    • 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,降低类之间的耦合性。

    1. 反射的优点和缺点:

      1. 优点:可以实现动态创建对象和编译,体现出很大的灵活性,

      2. 缺点:对性能有影响。使用反射基本上是一种操作解释, 我们告诉jvm 我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

这是在牛客上刷到的一道题考了对Java反射的理解。

A :Filed、Method Constructor分别分别用与描述类的与、方法和构造器。 在Java.lang.reflet包中而Class而是在Java.lang中

B:是对的 ,动态代理就是实现接口的 ,然后我们可以通过类的路径可以的到类的全部信息。(可以看下面的动态代理的原理)

反射常见的作用有:动态加载类、动态获取类的信息(属性、方法、构造器);

动态构造对象;动态调用类和对象的任意方法、构造器;

动态调用和处理属性;

获取泛型信息;处理注解

C:反射的概念中提到过 反射可以通过类的路径来得到该类的全部信息。

D:反射可以动态的调用类和对象的任意方法

E:反射的缺点是对性能有影响

F:反射会降低效率,可是设置禁止安全检查,来提高反射的运行速度;


2、动态代理的原理

由于通过上面反射是可以动态实现接口的 我们扯到了 动态代理,在明白动态代理之前我们要明白什么是代理,

什么是代理模式(Proxy)  给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

使用的场景有两种:

  • 客户端不想直接访问实际对象,或者访问实际的对象存在技术上的障碍, 因而通过代理对象作为桥梁来完成简介访问;
  • 在不改变目标对象方法的情况下对方法进行增强。

代理又分为静态代理和动态代理,

  • 静态代理:
    • 在不破坏接口实现类的同时又想新增一些功能 怎么办 ? 可以引出动态代理,其实就是创建一个实现接口类,且内部维护一个接口的成员变量指向原始接口的对象,通过代理对象的方法内部调用原始的接口实例的方法;
    • 代码如下:创建一个接口里面有一个方法。
1
2
3
public interface IDveloper {
public void writeCode();
}
1
2
3
4
5
6
7
8
9
10
public class Developer  implements  IDveloper{
private  String name;
public Developer(String name){
this.name = name;
}
public void writeCode() {
System.out.print("Developer " +name + " wrters code");
}
}
1
2
3
4
5
6
public class DeveloperTest {
public static void main(String[] args) {
IDveloper wrto = new Developer("wtao");
wrto.writeCode();
}
}



    • 静态代理的优点:

    • 容易理解和实现

    • 代理类和真实类的关系是编译期静态决定的,和动态代理比较起来,执行时没有任何额外开销

    • 静态代理的缺点:

    • 接口和代理时1对1的,有多个接口需要代理或接口中有多个方法,就需要创建多个代理类或者实现接口中的方法,繁琐

动态代理:

静态代理受限于接口的实现。而动态代理就是通过反射,动态的获取抽象接口的类型,从而获取相关特性进行代理。

使用动态的代理有三个步骤,

  • 创建一个代理执行类,,必须实现InvocationHandler 接口,表面该类是一个动态代理执行类。

  • 代理类需要实现InvocationHandler接口中的invoke(Object[] proxy,Method,Object[] args)方法【增强被代理类的功能或逻辑的方法】

  • 获取代理类,增强了功能,关键是要获取到代理类的对象,使用静态方法Proxy.newProxylnstance去获取代理的对象。

  • 代码如下:




获取代理类对象的方法,要传入的3个参数。

    • 第一个参数是类加载器

    • 第二个参数是委托类的接口类型,代理类返回的是同一个实现接口下的类型,保持代理类返回的类型;

    • 第三个参数就是代理类本身,就是告诉代理类,代理类遇到某个原视类的方法时该调用哪个代理执行下的invoke方法;

也可以在定义代理执行类时,直接在类中一个写出public方法来获取代理类的对象。

代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DeveloperProxy implements InvocationHandler {
private  Object target; //被代理的类
public Object getProxyInstance(Object target){
this.target = target;
Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
return  object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("还没睡呢? ");
Object result = method.invoke(target,args);
System.out.print("你还没睡呢? ");
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class DeveloperTest {
public static void main(String[] args) {
//创建被代理的对象
IDveloper wtao = new Developer("wato");
//创建被代理执行的对象
DeveloperProxy jdkProxy = new DeveloperProxy();
//将被代理对象交给代理类维护且获取代理类对象
IDveloper WtaoProxy = (IDveloper) jdkProxy.getProxyInstance(wtao);
WtaoProxy.writeCode();
}
}

静态代理类和动态代理类的区别

  • 静态代理类需要自己写代理类并一一实现目标方法,且代理类必须实现目标对象相同的接口。
  • 动态代理不需要自己实现代理类,它是利用JDKAPI,动态地子啊内存中构建代理对象需要我们传入被代理类,并且默认实现所有的目标方法。

【完】我是一块小饼干 麻烦大佬点个赞😁
#面试题目##Java工程师#
全部评论

相关推荐

点赞 评论 收藏
分享
评论
3
15
分享
牛客网
牛客企业服务