• 类的反射机制


    一,什么是反射机制??

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

    2,   简单的说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。包括其访问修饰符、父类、实现的接口、属性和方法的所有信息,并可在运行时创建对象、修改属性(包括私有的)、调用方法(包括私有的)。

    二,   为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态和静态的概念

    a)         静态编译:在编译时确定类型,绑定对象,即通过 Student stu=new Student(“zhangsan”,20);

    b)         动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的耦合性。

                Class.forName(“com.mysql.jdbc.Driver.class”).newlnstance();

    c)         反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是J2EE的开发中。

    d)         它的缺点是对性能有影响,使用反射基本上是一种解释操作,这类操作总是慢于直接执行的相同操作。

    三,生成对象的两种方式

    1,通过new对象的方式

       

    2,通过反射

      

             注意:forName("包名.类名"),且该方法仅支持默认构造一个对象。

           若想调用类的带有参数的构造函数,则采用下面方式:

         

           此方法可以通过调用类的任何构造函数来生成类的对象,用传入的参数来匹配构造函数。(注意:传入的是类型的Class对象)

          小提示:当一个类的构造函数被定义成私有的,说明该类不能在类外new对象了。

    四,获得类的类对象的三种方式

     1,Class   c = Student .class;

          该方法仅能将Student类的Class对象加载到内存,不会进行初始化。

     

        注意:要用类名.class,因为此时没有生成对象

     2,Class  c2=Class.forName(" 包名.要加载的类的类名");

         将类加载进来,并进行内存分配和初始化赋值

         此时借助的使Class对象的方法,并将包名.要加载的类的类名赋给该方法

       

      3.Student student =new Student("张三“,20,‘男’,”西安工业大学“);

         Class  c3=student.getClass();

        将类加载进来,并进行内存分配和初始化赋值,此时也会生成类的实例.

        注意:此时是通过生成对象的getClass()来进行类的加载。

     

    五,通过反射获取类的构造函数/变量/方法

    1,方法

     2,变量

    3.构造函数(同上)

    六,通过反射访问类的私有成员(必须要有对象)

        当一个类的的属性或方法被定义成私有的,此时通过new对象的方式是无法访问的,但是通过反射的方法,却可以访问到。

    1,通过反射调用方法。

          第一步:获取类的Class对象和生成对象:

                        Student student=new Student("张三",20,'男',"西安工业大学");

                        Class c=student.getClass();

                 还可以采用下面两种方法:

                  ******************************************

                

                  ******************************************

                

                  注意:当构造函数为私有的,要通过反射调用构造函数生成对象       

           

         第二步:获取变量/方法:

                方法:Method method=c.getDeclaredMethod("sing"); //将要获取的方法的名字传入

               变量:Field field=c.getDeclaredField("age"); //将要获取的变量的名字传入

         第三步:设置访问的变量或方法的访问权限

                        field.setAccessible(true);

          第四步:进行操作 ( 访问相应的成员,注意在使用这方法时,先要把对象传入,在传参数)

                         newInstance - 构造对象
                           invoke - 成员方法调用
                           set - 成员变量设置     
    get - 得到成员变量值

                           getName - 得到变量/方法/构造函数   的名字

     

     七,应用举例

         对于程序的开发模式之前一直强调:尽量减少耦合,而减少耦合的最好做法是使用接口,但是就算使用了接口也逃不出关键字new,所以实际上new是造成耦合的关键元凶。

    范例1:工厂设计模式

     1 package Factory_demo;
     2 
     3 interface Fruit {
     4     public void eat() ;
     5 }
     6 class Apple implements Fruit {
     7     public void eat() {
     8         System.out.println("吃苹果。");
     9     };
    10 }
    11 class Factory {
    12     public static Fruit getInstance(String className) {
    13         if("apple".equals(className)){
    14             return new Apple() ;
    15         }
    16         return null;
    17     }
    18 }
    19 public class Demo {
    20     public static void main(String[] args) {
    21         Fruit f = Factory.getInstance("apple") ;
    22         f.eat() ;
    23     }
    24 }

    以上为之前所编写最简单的工厂设计模式,但是在这个工厂设计模式之中有一个最大的问题:如果现在接口的子类增加了,那么工厂类肯定需要修改,这是它所面临的最大问题,而这个最大问题造成的关键性的病因是new,那么如果说现在不使用关键字new了,变为了反射机制呢?

    反射机制实例化对象的时候实际上只需要“包.类”就可以,于是根据此操作,修改工厂设计模式。

     1 package reflection_demo1;
     2 
     3 interface Fruit {
     4     public void eat() ;
     5 }
     6 class Apple implements Fruit {
     7     public void eat() {
     8         System.out.println("吃苹果。");
     9     };
    10 }
    11 class Orange implements Fruit {
    12     public void eat() {
    13         System.out.println("吃橘子。");
    14     };
    15 }
    16 
    17 class Factory {
    18     public static Fruit getInstance(String className) {
    19         Fruit f = null;
    20         try{
    21             f = (Fruit) Class.forName(className).newInstance() ;
    22         } catch(Exception e) {
    23             e.printStackTrace();
    24         }
    25         return f ;
    26     }
    27 }
    28 
    29 public class Demo {
    30     public static void main(String[] args) {
    31         Fruit f = Factory.getInstance("reflection_demo1.Orange") ;   //传参数 包名.类名
    32         f.eat() ;
    33     }
    34 }

     发现,这个时候即使增加了接口的子类,工厂类照样可以完成对象的实例化操作,这个才是真正的工厂类,可以应对于所有的变化。如果单独从开发角度而言,与开发者关系不大,但是对于日后学习的一些框架技术这个就是它实现的命脉,在日后的程序开发上,如果发现操作的过程之中需要传递了一个完整的“包.类”名称的时候几乎都是反射机制作用。

  • 相关阅读:
    Java最常见的面试题:模块十一
    Java最常见的面试题:模块九和模块十
    Java最常见的面试题:模块八
    Java最常见的面试题:模块七
    【leetcode】跳跃游戏
    【leetcode】字母异位词分组
    【C++】STL各容器的实现,时间复杂度,适用情况分析
    【C++】如何使用GCC生成动态库和静态库
    【C++】C++中基类的析构函数为什么要用virtual虚析构函数?
    【leet-code】接雨水
  • 原文地址:https://www.cnblogs.com/ljl150/p/11786077.html
Copyright © 2020-2023  润新知