一问Spring,就会涉及反射和动态代理,一般涉及到的是,概念,怎么用,好处,动态代理和静态代理的区别。
概念:面试的时候并没有人让我解释过反射,但是一般都是会问Spring ioc是什么,作用和好处,其实如果这么考察还是有很多可以说的。我理解ioc就是应用反射技术,来实现动态配置的,反射就是在运行时动态的获取一个类的信息,方法和属性,他不是在编译的时候就把类的相关信息就加载好的,因为之前我并不知道我能够用上它,这样的话等我用的时候我再去加载。有点类似延迟加载,动态应该就体现在运行时,而不是编译时的。
好处:java的反射机制就是增加程序的灵活性,避免将程序写死到代码里,例如: 实例化一个 person()对象, 不使用反射, new person(); 如果想变成 实例化 其他类, 那么必须修改源代码,并重新编译。使用反射: class.forName("person").newInstance(); 而且这个类描述可以写到配置文件中,如 **.xml, 这样如果想实例化其他类,只要修改配置文件的"类描述"就可以了,不需要重新修改代码并编译。其实这也是ioc和工厂模式的主要区别,知识点联系上了。
之前看题有个问Class.forName 和ClassLoader的区别:class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。应该就是介样子。
还可以继续问,一个对象的创建过程,比如Person p= new Person();
1虚拟机将.java文件转换成.class文件。2将.class文件加载进内存。3堆内存开辟空间,分配一个内存首地址。4进行属性分配,默认初始化。5对属性进行显示初始化。6进行实体的构造代码块初始化。7调用实体对应的构造函数,进行构造函数初始化。8将首地址赋值给p,p的变量就引用了该实体。
这个还可以继续引申为程序的初始化顺序:父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类非静态变量,父类非静态代码块,父类构造函数,子类非静态变量,子类非静态代码块,子类构造函数。(关于静态变量和静态代码块执行顺序是看你写的顺序)。
动态代理:
一般了解这个要提前了解下代理模式。这个模式面试中也会问到,简单撕下代码。概念就是:为其他对象提供一种代理以控制对象的访问。
手动撕了下代码,参看大话设计模式:
关于动态代理,一般会在Spring Aop中应用,上面写的代理模式是静态代理,动态代理就是想着运行时添加一些功能而又不影响程序的运行,不用重新编译。Aop就很好的应用了动态代理。也会问动态代理实现方式:一般是JDK的Proxy和Cglib。
1.JDK动态代理
此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
代理模式在实际使用时需要指定具体的目标对象,如果为每个类都添加一个代理类的话,会导致类很多,同时如果不知道具体类的话,怎样实现代理模式呢?这就引出动态代理。
JDK动态代理只能针对实现了接口的类生成代理。
CGLIB(CODE GENERLIZE LIBRARY)代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。如果目标对象没有实现接口,则默认会采用CGLIB代理;如果目标对象实现了接口,可以强制使用CGLIB实现代理。
缺点:动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。