• 反射


    1、java反射机制:Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

    2、Java反射机制主要提供了以下功能: 

    在运行时判断任意一个对象所属的类;

    在运行时构造任意一个类的对象;

    在运行时判断任意一个类所具有的成员变量和方法;

    在运行时调用任意一个对象的方法;

    生成动态代理。

    3、Class类:对于一个字节码文件.class,虽然表面上我们对该字节码文件一无所知,但该文件本身却记录了许多信息。Java在将.class字节码文件载入时,JVM将产生一个java.lang.Class对象代表该.class字节码文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制。所以要想完成反射操作,就必须首先认识Class类。

    java.lang.Class

    java.lang.reflet.Constructor

    java.lang.reflet.Field

    java.lang.reflet.Method

    java.lang.reflet.Parameter

    (1)java.lang.Class:Class类是一个比较特殊的类,它是反射机制的基础,Class类的对象表示正在运行的Java程序中的类或接口,也就是任何一个类被加载时,即将类的.class文件(字节码文件)读入内存的同时,都自动为之创建一个java.lang.Class对象。Class类没有公共构造方法,其对象是JVM在加载类时通过调用类加载器中的defineClass()方法创建的,因此不能显式地创建一个Class对象。通过这个Class对象,才可以获得该对象的其他信息。下表列出了Class类的一些常用方法。

     说明:通过getFields()和getMethods()方法获得权限为public成员变量和成员方法时,还包括从父类继承得到的成员变量和成员方法;而通过getDeclaredFields()和getDeclaredMethods()方法只是获得在本类中定义的所有成员变量和成员方法。 

      每个类被加载之后,系统都会为该类生成一个对应的Class对象,通过Class对象就可以访问到JVM中该类的信息,一旦类被加载到JVM中,同一个类将不会被再次载入。被载入JVM的类都有一个唯一标识就是该类的全名,即包括包名和类名。在Java中程序获得Class对象有如下3种方式。

    (1)使用Class类的静态方法forName(String className),其中参数className表示所需类的全名。如“Class cObj=Class.forName("java.lang.String");”。另外,forName()方法声明抛出ClassNotFoundException异常,因此调用该方法时必须捕获或抛出该异常。
    (2)用类名调用该类的class属性来获得该类对应的Class对象,即“类名.class”。如,语句“ClasscObj=Cylinder.class;”将返回Cylinder类所对应的Class对象赋给cObj变量。
    (3)用对象调用getClass()方法来获得该类对应的Class对象,即“对象.getClass()”。该方法是Object类中的一个方法,因此所有对象调用该方法都可以返回所属类对应的Class对象。如例8.8中的语句“Person per=new Person(“张三”);”可以通过以下语句返回该类的Class对象:Class cObj=per.getClass();
     
    注意:
      通过类的class属性获得该类所对应的Class对象,会使代码更安全,程序性能更好,因此大部分情况下建议使用第二种方式。但如果只获得一个字符串,例如获得String类对应的Class对象,则不能使用String.class方式,而是使用Class.forName("java.lang.String")。注意:如果要想获得基本数据类型的Class对象,可以使用对应的打包类加上.TYPE,例如,Integer.TYPE可获得int的Class对象,但要获得Intrger.class的Class对象,则必须使用Integer.class。在获得Class对象后,就可以使用表13.4中的方法来取得Class对象的基本信息。
    反射包reflet中的常用类
    (2)反射机制中除了上面介绍的java.lang包中的Class类之外,还需要java.lang.reflet包中的Constructor类、Method类、Field类和Parameter类。Java 8以后在java.lang.reflect包中新增了一个Executable抽象类,该类对象代表可执行的类成员。Executable抽象类派生了Constructor和Method两个子类。
    java.lang.reflect.Executable类提供了大量方法用来获取参数、修饰符或注解等信息,其常用方法如下表所示。
    getModifiers()方法返回的是以整数表示的修饰符。此时引入Modifier类,通过调用Modifier.toString(int mod)方法返回修饰符常量所应的字符串。
    java.lang.reflect.Constructor类是java.lang.reflect.Executable类的直接子类,用于表示类的构造方法。通过Class对象的getConstructors()方法可以获得当前运行时类的构造方法。java.lang.reflect.Constructor类的常用方法如下表所示。
    java.lang.reflect.Method类是java.lang.reflect.Executable类的直接子类,用于封装成员方法的信息,调用Class对象的getMethod()方法或getMethods()方法可以获得当前运行时类的指定方法或所有方法。下表是java.lang.reflect.Method类的常用方法。
    java.lang.reflect.Field类用于封装成员变量信息,调用Class对象的getField()方法或getFields()可以获得当前运行时类的指定成员变量或所有成员变量。java.lang.reflect.Field类的常用方法如下表所示。
    java.lang.reflect.Parameter类是参数类,每个Parameter对象代表方法的一个参数。java.lang.reflect.Parameter类中提供了许多方法来获取参数信息,下表给出了java.lang.reflect.Parameter类的常用方法。
    说明:使用javac命令编译Java源文件时,默认生成.class字节码文件中不包含方法的形参名信息,因此调用getName()方法不能得到参数的形参名,调用isNamePresent()方法将返回false。如果希望javac命令编译Java源文件时保留形参信息,则需要为编译命令指定-parameters选项。

    3、反射机制的优缺点:

    尽管反射机制带来了极大的灵活性及方便性,但反射也有缺点。反射机制的功能非常强大,但不能滥用。在能不使用反射完成时,尽量不要使用,原因有以下几点:
    (1)性能问题。
    Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射。而且,如何使用反射决定了性能的高低。如果它作为程序中较少运行的部分,性能将不会成为一个问题。
    (2)安全限制。
    使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
    (3)程序健壮性。
    反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化的时候,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。

    4、常见问题:

    (1)判断两个对象属于同一个类

    System.out.println(dd.getClass()==ayQueue.getClass());
  • 相关阅读:
    BZOJ1001 BJOI2006 狼抓兔子
    NOI2015 程序自动分析
    高斯消元法
    [POJ] 3666 Making the Grade
    [CODEVS] 2185 最长公共上升子序列
    [模板] LIS
    [CF] 219D Choosing Capital for Treeland
    [POJ] 2823 Sliding Window
    [BZOJ] 1072 [SCOI2007]排列perm
    [POJ] 1094 Sorting It All Out
  • 原文地址:https://www.cnblogs.com/guoyu1/p/12297758.html
Copyright © 2020-2023  润新知