• Java中反射机制详解


        序言

          在学习java基础时,由于学的不扎实,讲的实用性不强,就觉得没用,很多重要的知识就那样一笔带过了,像这个马上要讲的反射机制一样,当时学的时候就忽略了,到后来学习的知识中,很多东西动不动就用反射,所以回过头来把这个给重新补一下,自己欠下的债,迟早是要还的。

                                          ---WH

    一、什么是反射?

        在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。

        想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

        获取字节码文件对象的三种方式。

           1、Class clazz1 = Class.forName("全限定类名");  //通过Class类中的静态方法forName,直接获取到一个类的字节码文件对象,此时该类还是源文件阶段,并没有变为字节码文件。

           2、Class clazz2  = Person.class;    //当类被加载成.class文件时,此时Person类变成了.class,在获取该字节码文件对象,也就是获取自己, 该类处于字节码阶段。

           3、Class clazz3 = p.getClass();    //通过类的实例获取该类的字节码文件对象,该类处于创建对象阶段 

        有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。下面介绍Class类的功能。

    二、反射机制能够获取哪些信息?Class类的API详解。

        2.1、通过字节码对象创建实例对象

             

        2.2、获取指定构造器方法。constructor 如果没有无参构造,只有有参构造如何创建实例呢?看下面

             

          总结上面创建实例对象:Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的                             getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象

          获取全部构造方法  

                  

        2.3、获取成员变量并使用  Field对象

             获取指定成员变量

              

             Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值

            获取全部成员变量

            

        2.4、获得方法并使用  Method

              

            Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,    

              如果为私有方法,则需要打开一个权限。setAccessible(true);

            用invoke(Object, Object...)可以调用该方法,

            跟上面同理,也能一次性获得所有的方法

              

                   

        2.5、获得该类的所有接口

             Class[] getInterfaces():确定此对象所表示的类或接口实现的接口

             返回值:接口的字节码文件对象的数组

        2.6、获取指定资源的输入流

             InputStream getResourceAsStream(String name)  

             return:一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null

             参数:所需资源的名称,如果以"/"开始,则绝对资源名为"/"后面的一部分。

        2.7、动态代理的概述和实现

           动态代理:一种设计模式,其非常简单,很容易理解,你自己可以做这件事,但是觉得自己做非常麻烦或者不方便,所以就叫一个另一个人(代理)来帮你做这个事情,而你就不用管了,这就是动态代理。举个例子,买火车票叫人代买。 

           在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

           在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象 

            分三步,但是注意JDK提供的代理正能针对接口做代理,也就是下面的第二步返回的必须要是一个接口。

           1、new出代理对象,通过实现InvacationHandler接口,然后new出代理对象来。

           2、通过Proxy类中的静态方法newProxyInstance,来将代理对象假装成那个被代理的对象,也就是如果叫人帮我们代买火车票一样,那个代理就假装成我们自己本人

           3、执行方法,代理成功

              将代理对象中的内容进行实现

                   

                 

              

      

            1、2、3步

              

            注意newProxyInstance的三个参数,第一个,类加载器,第二个被代理对象的接口,第三个代理对象。  

           

        2.8、还有很多方法,比如获得类加载器,等等

           具体还需要别的,就通过查看API文档来解决。

    三、反射机制的应用实例

        3.1、利用反射,在泛型为int的arryaList集合中存放一个String类型的对象

           原理:集合中的泛型只在编译器有效,而到了运行期,泛型则会失效,

             

       3.2、利用反射,简化编写Servlet的个数。

            什么意思呢?每当我们写一个功能时,就需要写一个对应的Servlet,导致最后Servlet有很多,自己都看不过来,所以对其进行了优化,两种方式,

            3.2.1、每次从页面传过来一个参数,method="xxx"; 然后编写一个Servlet,获得其参数method的值,进行判断,如果是add,则调用add方法,如果是delete,则调用delete方法,这样就可以写在一个servlet中实现所有的功能了。 

            

          3.2.2、利用反射

            编写一个BaseServlet继承HttpServlet,这是一个通用的BaseServlet。需要明白servlet的生命周期

            

            编写具体实现的方法servlet类。

            MySerlvet001 extends BaseServlet

            

            

            解释:需要明白servlet的生命周期,也就是service方法,因为是servlet,所以在访问的时候,会经过service方法,而子类MyServlet001中并没有,所以就到父类BaseServlet中找,发现有,然后获取参数即知道了需要调用什么方法,因为方法的编写都在子类中,所以通过反射,获取到子类中对应的方法并运行,其中需要注意的是this这个参数在BaseServlet中的用法。需要理解它。才能理解我们这个程序。

    四、总结

          反射基本上就这样讲完了,其实就是对其一些api进行讲解,不懂的就查看API,重要的思想,就要在实际中遇到了才能得到更好的理解。先这样过一遍,零零碎碎的知识。

       

  • 相关阅读:
    LeetCode 485. Max Consecutive Ones
    LeetCode 367. Valid Perfect Square
    LeetCode 375. Guess Number Higher or Lower II
    LeetCode 374. Guess Number Higher or Lower
    LeetCode Word Pattern II
    LeetCode Arranging Coins
    LeetCode 422. Valid Word Square
    Session 共享
    java NIO
    非阻塞IO
  • 原文地址:https://www.cnblogs.com/shitaotao/p/7653228.html
Copyright © 2020-2023  润新知