【Java基础】易错面试题2,【反射和动态代理】(更新中...)
1、说一下Java中反射的概念和它的优缺点:
反射指的是在运行时能够分析类的能力的程序,首先说到反射我们需要知道在正常情况下,如果使用一个类,必须要经过一下几个步骤:
-
使用important导入类所在的包。
-
通过关键字new进行类对象实例化
-
产生对象可以使用“对象.属性” 来进行类中属性的调用
-
通过“对象.方法()”调用类中的方法
在反射中,使用一个类并不需要导入类所在的包,只要知道类的完整的路径就可以知道该类中的信息。反射并不需要有明确的类型对象,所有的对象使用Objiect表示。可以直接通过Object的与反射机制的混合调用类中的方法。简单来说,反射机制时程序在运行时能狗获取自身的信息。
在Java中,只要给定类的名字就可以通过反射机制来获取类的所有信息。
-
为什么要使用反射,它在实际编程中有什么应用
-
静态 编译: 在编译时确定类型,绑定对象即通过。
-
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,降低类之间的耦合性。
-
反射的优点和缺点:
-
优点:可以实现动态创建对象和编译,体现出很大的灵活性,
-
缺点:对性能有影响。使用反射基本上是一种操作解释, 我们告诉jvm 我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
-
这是在牛客上刷到的一道题考了对Java反射的理解。
A :Filed、Method Constructor分别分别用与描述类的与、方法和构造器。 在Java.lang.reflet包中而Class而是在Java.lang中
B:是对的 ,动态代理就是实现接口的 ,然后我们可以通过类的路径可以的到类的全部信息。(可以看下面的动态代理的原理)
反射常见的作用有:动态加载类、动态获取类的信息(属性、方法、构造器);
动态构造对象;动态调用类和对象的任意方法、构造器;
动态调用和处理属性;
获取泛型信息;处理注解
C:反射的概念中提到过 反射可以通过类的路径来得到该类的全部信息。
D:反射可以动态的调用类和对象的任意方法
E:反射的缺点是对性能有影响
F:反射会降低效率,可是设置禁止安全检查,来提高反射的运行速度;
2、动态代理的原理
由于通过上面反射是可以动态实现接口的 我们扯到了 动态代理,在明白动态代理之前我们要明白什么是代理,
什么是代理模式(Proxy) 给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
使用的场景有两种:
- 客户端不想直接访问实际对象,或者访问实际的对象存在技术上的障碍, 因而通过代理对象作为桥梁来完成简介访问;
- 在不改变目标对象方法的情况下对方法进行增强。
代理又分为静态代理和动态代理,
- 静态代理:
- 在不破坏接口实现类的同时又想新增一些功能 怎么办 ? 可以引出动态代理,其实就是创建一个实现接口类,且内部维护一个接口的成员变量指向原始接口的对象,通过代理对象的方法内部调用原始的接口实例的方法;
- 代码如下:创建一个接口里面有一个方法。
public interface IDveloper { public void writeCode(); }
public class Developer implements IDveloper{ private String name; public Developer(String name){ this.name = name; } @Override public void writeCode() { System.out.print("Developer " +name + " wrters code"); } }
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方法来获取代理类的对象。
代码如下:
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; } @Override 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; } }
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,动态地子啊内存中构建代理对象需要我们传入被代理类,并且默认实现所有的目标方法。
【完】我是一块小饼干 麻烦大佬点个赞😁