zoukankan      html  css  js  c++  java
  • Java反射

    java反射库(reflection library)提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序。这项功能被大量应用于JavaBeans中。

    能够分析类能力的程序称为反射。反射机制作用:

    1)运行时分析类的能力

    2)运行时查看对象

    3)实现通用的数组操作代码

    4)利用Method对象,这个对象类似于c++函数指针。

    Class类

    程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应方法执行。

    常用相关方法:

    static Class forName(String className)       //返回描述类名为className的Class对象

    static String getClass(Class classString)     //返回描述类名的String

    Object newInstance()  //返回这个类的新实例

    Object newInstance(Object[] args)  //构造一个这个构造器所属类的新实例,参数由args给出

    利用反射分析类

    反射机制最重要的内容--检查类的结构

    Class类中的相关方法:

    Field[] getFields()  //返回一个包含Field对象的数组,记录了这个类与其超类的公有域

    Field[] getDeclaredFields()  //返回一个包含Field对象的数组,记录了这个类的全部域

    Method[] getMethods()  //返回一个包含Method对象的数组,记录了所有的公有方法

    Method[] get DeclareMethods()  //返回一个包含Method对象的数组,记录了这个类所有或接口的所有方法

    Constructor[] getConstructors()  //返回一个包含Constructor对象的数组,记录了所有公有构造器

    Constructor[] getDeclareConstructors()  //返回一个包含Constructor对象的数组,记录了所有构造器

    反射包中相关方法:

    Class getDeclareClass()  //返回一个用于描述类中定义的构造器,方法或域的对象

    Class getExceptionTypes()  //返回一个用于描述方法抛出异常类型的Class对象数组

    int getModefiers()  //返回一个用于描述构造器,方法或域的修饰符的整形数值。使用Modefier类中的这个方法可以分析这个值

    String getName()  //返回一个用于描述构造器,方法或域名的字符串

    class[] getParrameterrTypes()  //返回一个用于描述参数类型的Class对象数组

    Class getReturnType()  //返回一个用于描述返回类型的Class对象

    static String toString(int modifiers)  //返回对应modefiers中位设置的修饰符的字符串表示

    static boolean isAbatract【或isFinal/isInterface.....所有修饰符】 (int modefiers)   //检测修饰符对应位  

    以下是一个测试用例:

    输入一个类,打印所有构造器,方法和域,包括他们的修饰符以及构造器和方法的参数

      1 package refleection.company;
      2 
      3 import java.lang.reflect.*;
      4 import java.util.Scanner;
      5 
      6 public class ReflectionTest {
      7 
      8     public static void main(String[] args) {
      9         String name;
     10         if (args.length > 0) {
     11             name = args[0];
     12         } else {
     13             Scanner in = new Scanner(System.in);
     14             System.out.println("Enter class name(e.g. java.util.Date):");
     15             name = in.next();
     16         }
     17 
     18         try {
     19             Class c1 = Class.forName(name);//获取对应类名的Class对象
     20             Class superc1 = c1.getSuperclass();//获取超类对象
     21             String modifiers = Modifier.toString(c1.getModifiers());//获取修饰符
     22             if (modifiers.length() > 0) {
     23                 System.out.print(modifiers + " ");
     24             }
     25             System.out.print("class " + name);
     26             if (superc1 != null && superc1 != Object.class) {
     27                 //打印超类对象
     28                 System.out.print("extends" + superc1.getName());
     29             }
     30             System.out.print("
    {
    ");
     31             printConstructors(c1);
     32             System.out.println();
     33             printMethods(c1);
     34             System.out.println();
     35             printFields(c1);
     36             System.out.println("}");
     37         } catch (ClassNotFoundException e) {
     38             e.printStackTrace();
     39         }
     40         System.exit(0);
     41     }
     42 
     43 
     44     public static void printConstructors(Class c1) {
     45         Constructor[] constructors = c1.getDeclaredConstructors();//获取所有构造器,存于数组
     46 
     47         for (Constructor c : constructors) {
     48             String name = c.getName();
     49             System.out.print(" ");
     50             String modifiers = Modifier.toString(c.getModifiers());//getModifiers返回一个描述修饰符的整数值,转为字符串
     51             if (modifiers.length() > 0) {
     52                 System.out.print(modifiers + " ");
     53             }
     54             System.out.print(name + "(");
     55             Class[] paramTypes = c.getParameterTypes();//获取描述参数类型的对象数组
     56             for (int j = 0; j < paramTypes.length; j++) {
     57                 if (j > 0) {
     58                     System.out.print(", ");
     59                 }
     60                 System.out.print(paramTypes[j].getName());
     61             }
     62             System.out.print(");");
     63         }
     64     }
     65 
     66     public static void printMethods(Class c1) {
     67         Method[] methods = c1.getDeclaredMethods();//获取所有方法,存于数组
     68 
     69         for (Method m : methods) {
     70             Class retType = m.getReturnType();//获取描述返回类型的对象
     71             String name = m.getName();
     72             System.out.print(" ");
     73             String modifiers = Modifier.toString(m.getModifiers());//描述修饰符的字符串
     74             if (modifiers.length() > 0) {
     75                 System.out.print(modifiers + " ");
     76             }
     77             System.out.print(retType.getName() + " " + name + "(");
     78             Class[] paramTypes = m.getParameterTypes();//获取描述参数类型的对象数组
     79             for (int j = 0; j < paramTypes.length; j++) {
     80                 if (j > 0) {
     81                     System.out.print(", ");
     82                 }
     83                 System.out.print(paramTypes[j].getName());
     84             }
     85             System.out.println(");");
     86         }
     87     }
     88 
     89     public static void printFields(Class c1) {
     90         Field[] fields = c1.getDeclaredFields();
     91 
     92         for (Field f : fields) {
     93             Class type = f.getType();//域所属类型
     94             String name = f.getName();
     95             System.out.print(" ");
     96             String modifiers = Modifier.toString(f.getModifiers());//域修饰符
     97             if (modifiers.length() > 0) {
     98                 System.out.print(modifiers + " ");
     99             }
    100             System.out.println(type.getName() + " " + name + ";");
    101         }
    102     }
    103 }
    View Code

    输入java.util.Date得到下面结果

     1 Enter class name(e.g. java.util.Date):
     2 java.util.Date
     3 public class java.util.Date
     4 {
     5  public java.util.Date(int, int, int, int, int, int); public java.util.Date(); public java.util.Date(int, int, int, int, int); public java.util.Date(java.lang.String); public java.util.Date(long); public java.util.Date(int, int, int);
     6  public void setYear(int);
     7  public int getMonth();
     8  public void setMonth(int);
     9  public void setDate(int);
    10  public int getDay();
    11  public int getHours();
    12  public void setHours(int);
    13  public int getMinutes();
    14  public void setMinutes(int);
    15  public int getSeconds();
    16  public void setSeconds(int);
    17  private final long getTimeImpl();
    18  static final long getMillisOf(java.util.Date);
    19  private static final java.lang.StringBuilder convertToAbbr(java.lang.StringBuilder, java.lang.String);
    20  public java.lang.String toLocaleString();
    21  public java.lang.String toGMTString();
    22  public int getTimezoneOffset();
    23  private final sun.util.calendar.BaseCalendar$Date getCalendarDate();
    24  private static final sun.util.calendar.BaseCalendar getCalendarSystem(long);
    25  private static final sun.util.calendar.BaseCalendar getCalendarSystem(sun.util.calendar.BaseCalendar$Date);
    26  private static final sun.util.calendar.BaseCalendar getCalendarSystem(int);
    27  private static final synchronized sun.util.calendar.BaseCalendar getJulianCalendar();
    28  public java.time.Instant toInstant();
    29  public static long UTC(int, int, int, int, int, int);
    30  public int getYear();
    31  public boolean before(java.util.Date);
    32  public boolean after(java.util.Date);
    33  public void setTime(long);
    34  public long getTime();
    35  public int getDate();
    36  public boolean equals(java.lang.Object);
    37  public java.lang.String toString();
    38  public int hashCode();
    39  public java.lang.Object clone();
    40  public int compareTo(java.util.Date);
    41  public volatile int compareTo(java.lang.Object);
    42  public static java.util.Date from(java.time.Instant);
    43  private void readObject(java.io.ObjectInputStream);
    44  private void writeObject(java.io.ObjectOutputStream);
    45  private final sun.util.calendar.BaseCalendar$Date normalize();
    46  private final sun.util.calendar.BaseCalendar$Date normalize(sun.util.calendar.BaseCalendar$Date);
    47  public static long parse(java.lang.String);
    48 
    49  private static final sun.util.calendar.BaseCalendar gcal;
    50  private static sun.util.calendar.BaseCalendar jcal;
    51  private transient long fastTime;
    52  private transient sun.util.calendar.BaseCalendar$Date cdate;
    53  private static int defaultCenturyStart;
    54  private static final long serialVersionUID;
    55  private static final [Ljava.lang.String; wtb;
    56  private static final [I ttb;
    57 }
    输出结果

    在运行时使用反射分析对象

    有时候希望可以看到数据域的实际数据而不只是类型,用反射同样可以做到。可能用到下列函数

    Object get(Object obj)  //返回obj对象中用Field对象表示的域值

    void set(Object obj,Object newValue)  //用一个新值设置obj对象中Field对象表示的域

    Field getField(String)  //获得指定名称的公有域

    Field getDeclareField(String)  //获得给定名称的域

    假设有一个Employee的类,该类有一个name私有域,根据以上函数,尝试获取域值

    Employee e = new Employee();
    Class c1 = e.getClass();
    Field f = c1.getDeclareField("name");
    Object v = f.get(e)

    看似可行,实际上时不可行的,它会抛出一个IllegalAccessException异常。name是私有域,java安全机制不允许没有访问权限的客户读取私有域的值,那么就要用到以下函数

    void setAccessible(boolean flag)  //为反射对象设置可访问标志

    boolean isAccessible()  //返回反射对象的可访问标志的值

    static void setAccessible(AccessibleObject[] array,boolean flag)  //设置对象数组可访问标志

    那么上述例子增加一条语句,就不会抛出异常了。

    f.setAccessable(true);

    以下是一个实例,输入任意类,输出它的所有域以及相应的值

     1 package objectAnalyzer;
     2 
     3 import java.lang.reflect.AccessibleObject;
     4 import java.lang.reflect.Array;
     5 import java.lang.reflect.Field;
     6 import java.lang.reflect.Modifier;
     7 import java.util.ArrayList;
     8 
     9 public class ObjectAnalyzer {
    10     private ArrayList<Object> visited = new ArrayList<>();
    11 
    12     public String toString(Object obj){
    13         if (obj==null){
    14             return "null";
    15         }
    16         if (visited.contains(obj)){
    17             return "...";
    18         }
    19         visited.add(obj);
    20         Class c1 = obj.getClass();//获取类名
    21         if (c1 == String.class){
    22             return (String)obj;
    23         }//若为String类型,直接返回String对象
    24         if (c1.isArray()){
    25             String r = c1.getComponentType()+"[]{";//getComponent返回表示数组元素类型的字符串
    26             for (int i = 0;i < Array.getLength(obj);i++){
    27                 if (i>0){
    28                     r += ",";
    29                 }//获取每个数值
    30                 Object val = Array.get(obj,i);
    31                 if (c1.getComponentType().isPrimitive()){//判断是否为基本类型
    32                     r += val;
    33                 }
    34                 else {
    35                     r += toString(val);
    36                 }
    37             }
    38             return r + "}";
    39         }
    40         String r = c1.getName();//非空,非String,非array,其他类
    41         do {
    42             r += "[";
    43             Field[] fields = c1.getDeclaredFields();//获取所有域
    44             AccessibleObject.setAccessible(fields,true);//设置为可见
    45             for (Field f:fields){
    46                 if (!Modifier.isStatic(f.getModifiers())){//非静态域
    47                     if(!r.endsWith("[")){
    48                         r += ",";
    49                     }
    50                     r += f.getName() + "=";//获取名称
    51                     try {
    52                         Class t = f.getType();
    53                         Object val = f.get(obj);
    54                         if (t.isPrimitive()){//判断是否为基本类型
    55                             r += val;
    56                         }
    57                         else {
    58                             r += toString(val);
    59                         }
    60                     }catch (Exception e){
    61                         e.printStackTrace();
    62                     }
    63                 }
    64             }
    65             r += "]";
    66             c1 = c1.getSuperclass();
    67         } while (c1 != null);
    68         return r;
    69     }
    70 }
    View Code
     1 package objectAnalyzer;
     2 
     3 import java.util.ArrayList;
     4 
     5 public class ObjectAnalyzerTest {
     6     public static void main(String[] args){
     7         ArrayList<Integer> squares = new ArrayList<>();
     8         for (int i = 1;i <= 5;i++){
     9             squares.add(i*i);
    10         }
    11         System.out.println(new ObjectAnalyzer().toString(squares));
    12     }
    13 
    14 }
    测试类

    结果

    1 java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=1][][],java.lang.Integer[value=4][][],java.lang.Integer[value=9][][],java.lang.Integer[value=16][][],java.lang.Integer[value=25][][],null,null,null,null,null},size=5][modCount=5][][]
    View Code

    使用反射编写泛型数组代码

    java反射包中的Array类允许动态地创建数组,将其拓展为更通用的方法,即可以拓展任意类型的数组。

    public static Object goodCopyOf(Object a,int length){
        Class c1 = a.getClass();
        if(!c1.isarray()){
            return null;
        }
        Class componentType = c1.getComponentType();
        int length = Array.getLength(a);
        Object newArray = Array.newInstance(ComponentType, newLength);
        System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
        return newArray;
    }

    Array类的一些方法

    static Object get(Object array,int index) //返回给定数组下标的内容

    static xxx getXxx(Object array,int index) //返回给定数组下标的内容,xxx是基本类型

    static void set(Object array,int index,Object newValue)  //设置指定下标内容

    staticc int getLength(Object array)  //返回数组长度

    static Object newInstance(Class componentType,int length)  //返回一个具有给定类型,维数的新数组

    static Object newInstance(Class componentType,int[] length)

    调用任意方法

    Methods类中有一个invoke方法,允许调用包装在当前Method对象中的方法。如下:

    public Object invoke(Object implicitParameter,Object[] explicitParamenters)  //调用这个对象描述的方法,传递给定参数,返回方法的返回值。对于静态方法,把null作为隐式参数传递。

  • 相关阅读:
    Spring集成MyBatis
    UpdatePanel的简单用法(转)
    updatePanel导致JS失效的解决办法(转)
    sql面试题(学生表_课程表_成绩表_教师表)
    javascript深入理解js闭包
    T-SQL利用Case When Then多条件判断
    T-SQL排名函数
    DataTable字符串类型的数字,按照数字类型排序
    Sql 行转列问题总结
    行转列:SQL SERVER PIVOT与用法解释
  • 原文地址:https://www.cnblogs.com/lht-record/p/8367483.html
Copyright © 2011-2022 走看看