Java面试常考点:-----反射机制

1.定义: 什么是反射?

​ 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。

2.用途:

​ 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

3. 哪里用到反射机制?

  1. JDBC中,利用反射动态加载了数据库驱动程序。

  2. Web服务器中利用反射调用了Sevlet的服务方法。

  3. Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。

  4. 很多框架都用到反射机制,注入属性,调用方法,如Spring框架中AOP(动态代理:代理类是动态生成的)。

  5. 读取配置文件等

4. 动态代理是什么?有哪些应用?

  1. 角色分析:

    • 抽象角色:一般会使用接口或者抽象类来解决(如租房)
    • 真实角色:被代理的角色(如房东)
    • 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作。(如中介收中介费,带他们去看房子)
    • 客户:访问代理对象的人!(要去租房的人)
  2. 动态代理:是运行时动态生成代理类。

  3. 动态代理的应用有 Spring AOP面向切面编程、测试框架的后端 mock、rpc,Java注解对象获取等。

5. 怎么实现动态代理?

1.基于接口的动态代理

2.基于类的动态代理

  • 基于接口——JDK动态代理(原生)【我们在这里使用】
  • 基于类:cglib
  • java字节码实现:javasisit【多点,在JBoss】

需要了解两个类:

  • Proxy:代理,生成代理类

  • InvocationHandler:调用处理程序,处理代理实例,并返回结果

通用代理类:

package edu.xalead.demo4;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {
     
    //被代理接口(组合)
    private Object tar;

    public void setTar(Object tar) {
     
        this.tar = tar;
    }

    //生成代理类
    public Object getProxy(){
     
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),tar.getClass().getInterfaces(),this);
    }
    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        Object res = method.invoke(tar,args);
        return res;
    }

}

6. 反射机制的优缺点?

  1. 优点:

    • 可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性(使得Java成为半动态语言)。

    • 反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类

  2. 缺点:

    • 对性能有影响,这类操作总是慢于直接执行java代码,使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

    • 使用反射会模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

    • 而且有一定的安全性问题,我们可以访问到私有属性。

7. Java反射机制的作用

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的方法

8. 如何使用Java的反射?

  1. 通过一个全限类名创建一个对象Cls

    1. Class.forName(“全限类名”); 例如:com.mysql.jdbc.Driver Driver类已经被加载到 jvm中,并且完成了类的初始化工作就行了
    2. 类名.class; 获取Class<?> cls对象
    3. 对象.getClass();
    4. .特殊的如:Integer.TYPE
  2. 获取构造器对象,通过构造器new出一个对象

    1. Cls.getConstructor([String.class]);
    2. Cls.newInstance([参数]);
  3. 通过class对象创建一个实例对象(就相当与new类名()无参构造器)

    1. Cls.newInstance();//默认调用午餐构造
  4. 通过class对象获得一个属性对象

    1. Field c=Cls.getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。
    2. Field c=Cls.getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的声明字段
  5. 通过class对象获得一个方法对象

    1. Cls.getMethod(“方法名”,class……parameaType);(只能获取公共的)
    2. Cls.getDeclareMethod(“方法名”);(获取任意修饰的方法,不能执行私有)
    3. Cls.setAccessible(true);(让私有的方法可以执行,可以提高效率,不让jvm检查合法性)
  6. 让方法执行
    1). Method.invoke(obj实例对象,obj可变参数);-----(是有返回值的)

    这是一个工具类,让一个servlet实现多个请求方法。

    package edu.xalead.web.servlet.backend.Utils;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.Method;
    
    public class BaseServlet extends HttpServlet {
           
    
        //基类servlet 进行了深层的封装
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           
            doGet(request, response);
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           
            //请求头 :Get uri?method=add Http/1.1
            //取出method
            String method = request.getParameter("method");
    
            //通过反射获取里面的方法
            Class c = this.getClass();
            try {
           
                Method m = c.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
                m.setAccessible(true);
                m.invoke(this, request, response);
            } catch (Exception e) {
           
                e.printStackTrace();
            }
        }
    }
    

    请求的时候根据method参数来判断调用哪个servlet方法

    <c:forEach items="${list}" var="row">
        · <a href="/mainServlet?method=seeArticle&id=${row[0]}">${row[1]}a>
    c:forEach>
    

9.最后谈谈什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作?

  1. 对象序列化,将对象中的数据编码为字节序列的过程。
  2. 反序列化;将对象的编码字节重新反向解码为对象的过程。
  3. JAVA提供了API实现了对象的序列化和反序列化的功能,使用这些API时需要遵守如下约定:
    1. 被序列化的对象类型需要实现序列化接口,此接口是标志接口,没有声明任何的抽象方法,JAVA编译器识别这个接口,自动的为这个类添加序列化和反序列化方法。
    2. 为了保持序列化过程的稳定,建议在类中添加序列化版本号。
    3. 不想让字段放在硬盘上就加transient
  4. 以下情况需要使用 Java 序列化:
    1. 想把的内存中的对象状态保存到一个文件中或者数据库中时候;
    2. 想用套接字在网络上传送对象的时候;
    3. 想通过RMI(远程方法调用)传输对象的时候。

欢迎访问我的个人博客交流学习:http://www.ayjup.cn

你可能感兴趣的:(反射)