美文网首页
Java中的反射机制

Java中的反射机制

作者: 周二鸭 | 来源:发表于2019-02-24 10:59 被阅读1次

    一、反射的理解

    (1)正射
    在引入发射这个概念前,需要先理解“正射”。
    在一般的情况下,我们使用某个类的时候,必定是了解它是什么类,是用来做什么的,有怎样的功能。于是我们可以对这个类进行实例化,之后再使用实例化的对象对这个类进行操作。

    Person person = new Person();
    person.sleep("8:00");
    

    (2)反射
    上面的例子简单的介绍了什么为“正射”,以及“正射”的一般例子。
    而反射则是在一开始并不知道要初始化的类是什么,自然也无法使用new关键字来创建对象了。
    而当我们可以的到这个类的名称时,我们就可以使用JDK提供的反射API进行反射调用。

    Class clazz = Class.forName("com.reflect.Person");
    Method method = clazz.getMethod("sleep", String.class);
    Constructor constructor = clazz.getConstructoer();
    Object object = constructor.newInstance();
    method.invoke(object, "8:00");
    

    以上的两段代码,其结果都是一致的,但是其思路却是完全不一样:

    • 第一段代码在未运行前就已经确定了要运行的类(Person);
    • 第二段代码则是在整个程序运行时从某些地方(例:配置文件)获取到相应的字符串值才能知道要运行的类(cn.reflect.Person);

    二、反射的应用

    (1) Tomcat中的类读取创建:

    <servlet>
            <servlet-name>ChatServlet</servlet-name>
            <servlet-class>chat.ChatServlet</servlet-class>
        </servlet>
    <servlet-mapping>
            <servlet-name>ChatServlet</servlet-name>
            <url-pattern>/servlets/chat/chat</url-pattern>
    </servlet-mapping>
    

    由上所示,当一个HTTP请求过来时,Servlet容器首先会通过映射器选择到相应的Servlet类,再通过web.xml配置文件中的类的地址实例化一个Servlet对象,然后再通过固定的方法名去调用Servlet中的方法。

    三、反射中的常用函数

    (1)获取反射中的class对象
    在反射中,要获取一个类或调用一个类的方法,首先必须要获取到该类的对象,在Java API中,获取Class类对象有三种方法:
    ①:Class.forName("-类的路径名-");

    Class clazz = Class.forName("com.reflect.Person");
    

    ②:利用以有类对象的getClass()方法;

    Person person = new Person();
    Class clazz = person.getClass();
    

    ③:对于在编译前就已知道的类,可以使用.class方法。

    Class clazz = Person.class;
    

    (2)通过反射创建类对象
    通过反射创建类的对象,Java API提供了两种方式:
    ①:通过Class对象的newInstance()方法;

    Class clazz = Class.forName("com.reflect.Person");
    Person person = (Person)clazz.newInstance();
    

    ②:通过Constructor对象的newInstance()方法

    Class clazz = Class.forName("com.reflect.Person");
    Constructor con = clazz.getConstructor();
    Person person = (Person)con.newInstance();
    

    注意:通过Constructor对象的newInstance()方法创建类对象可以选择特定的构造函数,而通过Class对象的newInstance()方法则只能使用默认的无参构造函数。例:

    Class clazz = Class.forName("com.reflect.Person");
    Constructor con = clazz.getConstructor();
    Person person = (Person)con.newInstance("张三");
    

    (3)通过反射操作成员变量
    ①:获取所有成员getFields()&getDeclaredFields()
    使用getFields()方法可以获取Class类的成员变量,但是无法获取私有属性。

    Class clazz = Class.forName("com.reflect.Person");
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
      System.out.print(field.getName());
    }
    

    ②:获取单个成员getField()&getDeclaredField()
    ③:修改成员的值set(Object obj, Object value)

    Class clazz = Class.forName("com.reflect.Person");
    Person person = (Person)clazz.newInstance();
    Field field = clazz.getField("name");
    field.set(person, "张三");
    

    当属性为private时,你无法修改它的值,此时应使用setAccessible()方法取得访问权限

    Class clazz = Class.forName("com.reflect.Person");
    Person person = (Person)clazz.newInstance();
    Field field = clazz.getDeclaredField("name");
    field.setAccessible(true);
    field.set(person, "张三");
    

    (4)通过反射操作成员方法
    ①:获取所有方法getMethods()&getDeclaredMethods()
    ②:获取单个成员getMethod()&getDeclaredMethod()
    操作方法与操作变量相差不大,在获取到对应方法后使用invoke()方法即可执行。同理,遇见私有方法时,也需要使用setAccessible(true)方法获取访问权限。

    Class clazz = Class.forName("com.reflect.Person");
    Person person = (Person)clazz.newInstance();
    Method method = clazz.getMethod("setName", String.class);
    method.setAccessible(true);
    method.invoke("李四");
    

    注:通常情况下,即便是当前类,private方法或属性也是没有权限访问的,你需要设置压制权限setAccessible(true)来取得访问权限,但实际上,这已经破坏了规则,所以应该尽量少使用。

    相关文章

      网友评论

          本文标题:Java中的反射机制

          本文链接:https://www.haomeiwen.com/subject/fasmyqtx.html