zoukankan      html  css  js  c++  java
  • java笔记反射机制之基础总结与详解

    一.反射之实例化Class类的5种方式:

    java的数据类型可以分为两类,即引用类型和原始类型(即基本数据类型)。
    对于每种类型的对象,java虚拟机会实例化不可变的java.lang.Class对象。
    它提供了在运行时检查对象属性的方法,这些属性包括它的成员和类型信息。

    更重要的是Class对象是所有反射API的入口。

    Class类是泛型类,可以使用@SuppressWarnings("unchecked")忽略泛型或者使用Class<V>类型。

    获得Class对象的5种方式:


    1."Object.getClass()"   : 如果一个类的对象可用,则最简单的获得Class的方法是使用Object.getClass()。
                                        当然,此方式只对引用类型有效。

    2. ".class"------------- : 如果类型可用但没有对象,则可以在类型后加上".class"来获得Class对象。这也是使原始类型
                                        获得Class对象最简单的方式:
    3."Class.forName()"---:  如果知道类的全名,则可以使用静态方法Class.forName()来获得Class对象,它不能用在原始类型上,

                                        但是可以用在原始类型数组上。(注:此方式会抛出ClassNotFoundException异常)
    4. "包装类的TYPE域"-----:  每一个原始类型和void都有包装类。利用其TYPE域就可以获得Class对象。


    5."以Class为返回值的方法": 如获取内部类的getDeclaredClasses()方法,此时返回一个对象数组

     --支持知识共享,转载请标注地址"http://www.cnblogs.com/XHJT/p/3915221.html  "——和佑博客园,谢谢~~--

    代码实例:

    package com.xhj.reflection_excetion;
    
    /**
     * 反射之实例化Class类的5种方式
     * 
     * @author XIEHEJUN
     * 
     */
    public class InstantiateClassObject {
    
        @SuppressWarnings("rawtypes")
        public static void main(String[] args) throws ClassNotFoundException {
            System.out.print("第一种方式--用Object.getClass()方法获取到的String类的对象为: ");
            Class class1 = new String().getClass();
            System.out.println(class1.getName());    
            
            System.out.print("第二种方式--用.class()方法获取到的String类的对象为: ");
            class1 = String.class;
            System.out.println(class1.getName());
            
            System.out.print("第三种方式--用.forName()方法获取到的String类的对象为: ");
            class1 = Class.forName("java.lang.String");
            System.out.println(class1.getName());
            
            System.out.print("第四种方式--用包装类的TYPE域获取到的Integer类的对象为: ");
            class1 = Integer.TYPE;
            System.out.println(class1.getName());
            
            System.out.println("第五种方式--用getDeclaredClasses()获取String类的内部类对象:");
            Class<?>[] clazz = new String().getClass().getDeclaredClasses();
            for (Class<?> class2 : clazz) {
                System.out.println("\t"+class2);
            }
            
    
        }
    
    }

    结果为:

    结果


    注:除了java.lang.reflect.ReflectPermission和java.lang.reflect包外,所有类都没有公共的
    构造方法。为了获得这些类的对象,必须使用Class类中适当的方法,对于不同的数据类型,Class
    对象的获得方式是不同。

    二.反射之查看类的定义:

       通常类的声明包括常见修饰符(public,protected,private,abstract,static,final,strictfp等)、
        类的名称、类的泛型参数、类的继承类(实现的接口)、类的注解等信息。

       
        Class类的实例表示正在运行的Java应用程序中的类和接口:
        枚举是一种类,注释是一种接口。
        每一个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象;
        基本数据类型和关键字void也表示为Class对象。
        Class没有公共的构造方法。
        Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
       
        Class类常用方法:
        forName(String className)-: 根据给定的名称获得Class对象
       getAnnotations()------------: 返回此Class对象上存在的注释
       getCanonicalName() --------: 返回Java Language Specification 中所定义的底层类的规范化名称
        getGenericInterfaces()------: 返回泛型形式的对象类所实现的接口
        getGenericSuperclass() -----: 返回泛型形式的对象类所直接继承的超类
        getModifuers() --------------: 返回此类或接口以整数编码的Java语言修饰符
        getTypeParameters() -------: 按声明顺序返回TypeVariable对象的一个数组


       注:Java语言预定义的注解只有@Deprecated可以在运行时获得。   
       
    实例代码:

    package com.xhj.reflection_excetion;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Type;
    import java.lang.reflect.TypeVariable;
    
    /**
     * 查看类的定义
     * 
     * @author XIEHEJUN
     * 
     */
    public class CheckClassStatement {
    
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> classtest = Class.forName("java.util.ArrayList");
            System.out.println("1.根据给定的名称获得Class对象:" + classtest.getName());
            Annotation[] annotations = classtest.getAnnotations();
            System.out.print("2.获取此对象上的注解为:");
            if (annotations.length > 0) {
                for (Annotation annotation : annotations) {
                    System.out.println(annotation + "\t");
                }
            } else {
                System.out.println("空");
            }
    
            System.out.println("3.获得Java语言规范化名称:" + classtest.getCanonicalName());
    
            System.out.println("4.获取类上的修饰符:共有" + classtest.getModifiers()
                    + "个,为: " + Modifier.toString(classtest.getModifiers()));
    
            TypeVariable<?>[] typeV = classtest.getTypeParameters();
            System.out.print("5.在对象上获取到的泛型是:");
            if (typeV.length > 0) {
                for (TypeVariable<?> typeVariable : typeV) {
                    System.out.println(typeVariable);
                }
            } else {
                System.out.println("空");
            }
    
            System.out.println("6.在对象上获取到的接口为:");
            // 使用getInterfaces()不包含泛型;使用getGenericInterfaces包含泛型
            Type[] intefaces = classtest.getGenericInterfaces();
            if (intefaces.length > 0) {
                for (Type type : intefaces) {
                    System.out.println("\t" + type);
                }
            } else {
                System.out.println("空");
            }
            Class class2 = classtest.getSuperclass();
            System.out.print("7.在对象上获取直接继承类:");
            if (class2 != null) {
                System.out.println(class2);
            } else {
                System.out.println("空");
            }
    
        }
    }

    结果为:

    结果


    注:getSuperclass()方法也不能获得有泛型信息的父类

    三.反射之获得Class对象表示实体的名称

    对于不同类型的对象,其Class对象的名称是不同的,反过来说就是从这个名称就可以知道该对象的类型。

    注:
        1.如果此类对象表示的是非数组类型的引用类型,则返回该类的二进制名称。
        2.如果此类对象表示一个基本类型或者void,则返回其对应的Java语言的关键字的字符串。
        3.如果此类对象表示一个数组类,名字的内部形式为"[元素编码",其深度为几维,就有几个"["。
            其元素类型编码为:
            ——————————————————————————————————————————————————
               元素类型                       编 码          
               boolean                         Z
               byte                              B
               char                              C
               short                             S
               int                                 I
               float                              F
               double                           D
               long                              J
               class or interfaces       Lclassname(即当元素是引用类型或者接口的时候,编码为"L+类名")
            ____________________________________________________

    实例代码:

    package com.xhj.reflection_excetion;
    
    /**
     * 获取对象实体的名称
     * 
     * @author XIEHEJUN
     * 
     */
    public class GetClassEntityName {
        /**
         * 数组元素类型编码为:
         * 元素类型                       编码 
         * boolean                     Z 
         * byte                       B 
         * char                       C 
         * short                      S 
         * int                        I 
         * float                      F 
         * double                     D 
         * long                       J 
         * class or interfaces    Lclassname(即当元素是引用类型或者接口的时候,编码为"L+类名")
         */
        public static void main(String[] args) {
            System.out.println("获取非数组类型的引用类型,返回该类的二进制名称: "
                    + new String().getClass().getName());
            System.out.println("获取基本类型,返回其对应的Java语言的关键字的字符串: "
                    + int.class.getName());
            System.out.println("获取void类型,返回其对应的Java语言的关键字的字符串: "
                    + void.class.getName());
            System.out.println("获取一维数组类型的基本类型,返回'[+元素编码': "
                    + new int[2].getClass().getName());
            System.out.println("获取一维数组类型的引用类型,返回'[+元素编码': "
                    + new String[2].getClass().getName());
            System.out.println("获取二维数组类型的基本类型,返回'[+元素编码': "
                    + new int[2][3].getClass().getName());
            System.out.println("获取二维数组类型的引用类型,返回'[+元素编码': "
                    + new String[2][3].getClass().getName());
            System.out.println("用getCanonicalName()获取二维数组类型的基本类型,返回数组名称"
                    + new int[2][3].getClass().getCanonicalName());
            System.out.println("用getCanonicalName()获取二维数组类型的引用类型,返回数组名称"
                    + new String[2][3].getClass().getCanonicalName());
        }
    
    }

    结果为:

    结果

    注:
    对于数组来说,用getCanonicalName()方法可以获取的到数组的名称,且比较容易接受和辨认

    四.反射之查看类的成员

    我们要查看类的定义,首先想到的当然是API文档,但若是找不到API文档又该如何呢?此时就要用到Java的反射机制了。
    另外我们在无法查看源代码的情况下,也可以通过反射机制查看类的成员,包括"域,构造方法,普通方法和内部类"等。

       主要用到的方法:
        getConstructors() -------: 返回由该类对象的所有构造方法组成的数组
        getDeclaredFields() -----:  返回由该类对象的所有非继承域组成的数组
        getDeclaredMethods() -- :  返回由该类对象的所有非继承方法组成的数组
        getFields() -------------- :  返回由该类对象的所有公共域组成的数组
       getMethod() -------------:  返回由该类对象的所有公共方法组成的数组

    代码实例:

    package com.xhj.reflection_excetion;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /**
     * 查看类的成员
     * 
     * @author XIEHEJUN
     * 
     */
    public class CheckClassMembers {
    
        public static void main(String[] args) {
            Class<?> strclass = new String().getClass();
    
            // 查看构造方法
            System.out.println(strclass.getName() + "的构造方法有:");
            Constructor<?>[] constructors = strclass.getConstructors();
            if (constructors.length > 0) {
                for (Constructor<?> constructor : constructors) {
                    System.out.println("\t" + constructor);
                }
            } else {
                System.out.println("空");
            }
            // 查看非继承域
            System.out.println(strclass.getName() + "的非继承域有:");
            Field[] declaredFields = strclass.getDeclaredFields();
            if (declaredFields.length > 0) {
                for (Field field : declaredFields) {
                    System.out.println("\t" + field);
                }
            } else {
                System.out.println("空");
            }
    
            // 查看非继承方法
            System.out.println(strclass.getName() + "的非继承方法有:");
            Method[] declaredMethods = strclass.getDeclaredMethods();
            if (declaredMethods.length > 0) {
                for (Method method : declaredMethods) {
                    System.out.println("\t" + method);
                }
            } else {
                System.out.println("空");
            }
    
            // 查看所有公共域
            System.out.println(strclass.getName() + "的所有域有:");
            Field[] fields = strclass.getFields();
            if (fields.length > 0) {
                for (Field field : fields) {
                    System.out.println("\t" + field);
                }
            } else {
                System.out.println("空");
            }
    
            // 查看所有公共的方法
            System.out.println(strclass.getName() + "的所有继承方法有:");
            Method[] methods = strclass.getMethods();
            if (methods.length > 0) {
                for (Method method : methods) {
                    System.out.println("\t" + method);
                }
            } else {
                System.out.println("空");
            }
        }
    
    }

    结果为:

    (打印出来的数据太多,这里之展示部分结果~)

    结果

    注:对于私有域或方法,如果有安全管理器,可能会报异常。

    五:反射之查看内部类消息

    Class类的getDeclaredClasses()方法返回Class对象的一个数组,这些对象反映声明为该Class对象
    所表示的类的成员的所有类和接口,包括该类所声明的公共、保护、默认(包)访问及私有类和接口,
    但不包括继承的类和接口。若该类不将任何类或接口声明为成员,或者该对象表示基本类型、数组类或
    void,则该方法返回一个长度为0的数组。
            public Class<?> [] getDeclaredClasses() throws SecurityException

    注:利用Class类的getDeclaredClasses()方法可以获得一个数组,其中的每一个成员代表一个内部类的类对象。
    然后我们可以像获取普通类的信息一样,获取到内部类的信息。
              
    代码实例:

    package com.xhj.reflection_excetion;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    /**
     * 查看内部类的消息
     * 
     * @author XIEHEJUN
     * 
     */
    public class CheckInnerClass {
    
        public static void main(String[] args) {
            Class<?> clazz = new String().getClass();
            Class[] class1 = clazz.getDeclaredClasses();
            for (int i = 0; i < class1.length; i++) {
                Class<?> innerclass = class1[i];
                System.out
                        .println("================================================================");
                System.out.println("内部类" + i + "为: " + innerclass.getName());
    
                System.out.println("内部类" + i + "的父类为:"
                        + innerclass.getSuperclass().getName());
    
                System.out.print("内部类" + i + "的所有公共域为:");
                Field[] field = innerclass.getFields();
                if (field.length > 0) {
                    System.out.println();
                    for (Field field2 : field) {
                        System.out.println("\t" + field2);
                    }
                } else {
                    System.out.println("空");
                }
    
                System.out.print("内部类" + i + "的非继承域为:");
                Field[] declaredfield = innerclass.getDeclaredFields();
                if (declaredfield.length > 0) {
                    System.out.println();
                    for (Field field2 : declaredfield) {
                        System.out.println("\t" + field2);
                    }
                } else {
                    System.out.println("空");
                }
    
                System.out.print("内部类" + i + "的所有公共方法为:");
                Method[] methods = innerclass.getMethods();
                if (methods.length > 0) {
                    System.out.println();
                    for (Method method : methods) {
                        System.out.println("\t" + method);
                    }
                } else {
                    System.out.println("空");
                }
    
                System.out.print("内部类" + i + "的非继承方法为:");
                Method[] declaredmethods = innerclass.getDeclaredMethods();
                if (declaredmethods.length > 0) {
                    System.out.println();
                    for (Method method : declaredmethods) {
                        System.out.println("\t" + method);
                    }
                } else {
                    System.out.println("空");
                }
    
            }
    
        }
    
    }

    结果为:

    (打印出来的数据太多,这里之展示部分结果~)

    结果


    六.反射之按继承层次对类排序

    Java提供了instanceof运算符来比较两个类(或接口)之间是否存在继承关系。
    但是对于多个类来说,这种方法是很麻烦的。这时候,我们要做的应该是利用
    java的反射机制来对存在继承关系的类进行排序。

    主要方法:

    TreeSet<E> 是基于TreeMap的NavigableSet实现的。它使用元素的自然顺序对
    元素进行排序,或者根据创建set时提供的Comparator进行排序,具体取决于
    使用的构造方法。本节采用Class类中的isAssignableFrom()方法来判断当前
    Class 对象所表示的类与给定的Class对象所表示的类之间的关系,若相同或
    是父类则返回true,否则返回false。
       public boolean isAssignableFrom(Class<?> clazz)
       
    注:Java中与排序相关的接口有Comparable和Comparator。这两个接口通过对象之
    间比较的结果--一个有符号的整数来比较对象的大小。实现任何一个接口都可
    以让对象具有排序的能力。固可以用TreeSet也可以用Arrays.sort()来进行排序。

    代码实例:

    package com.xhj.reflection_excetion;
    
    import java.awt.Container;
    import java.util.Comparator;
    import java.util.TreeSet;
    
    import javax.swing.JComponent;
    import javax.swing.JPanel;
    
    /**
     * 比较并将类按继承关系排序
     * 
     * @author XIEHEJUN
     * 
     */
    public class CompareClasses implements Comparator<Class<?>> {
    
        @Override
        public int compare(Class<?> o1, Class<?> o2) {
            if (o1.equals(o2)) {
                return 0;
            } else if (o1.isAssignableFrom(o2)) {
                return -1;
            } else if (o2.isAssignableFrom(o1)) {
                return 1;
            } else {
                throw new IllegalArgumentException(o1+"和"+o2+"两个类之间没有联系");
            }
        }
    
        public static void main(String[] args) {
            TreeSet<Class<?>> treeSet = new TreeSet<Class<?>>(
                    new CompareClasses());
            System.out.println("添加类——JComponent.class");
            treeSet.add(JComponent.class);
            System.out
            .println("添加类——Container.class");
            treeSet.add(Container.class);
            System.out.println("添加类——JPanel.class");
            treeSet.add(JPanel.class);
            System.out.println("=================排序后为=====================");
            for (Class<?> class1 : treeSet) {
                System.out.println(class1);
            }
        }
    
    }

    结果为:

    结果

    知识重在总结和梳理,只有不断地去学习并运用,才能化为自己的东西。由于本人进阶猿类时间尚短,故此博客即是我学习,工作的笔记,也是和大家交流,相互提升技术的平台~希望大家不吝赐教~~ --但管努力,莫问前程,事在人为,功不唐捐。--和佑博客园
  • 相关阅读:
    session和cookie
    数据库备份
    使用pip安装.whl文件时出现is not a supported wheel on this platform的解决办法
    multiprocessing模块
    threading模块
    python中多线程相关
    python中实现单例模式
    Flask-SQLAlchemy相关与Flask-Migrate相关
    redis模块
    Flask-Login中装饰器@login_manager.user_loader的作用及原理
  • 原文地址:https://www.cnblogs.com/XHJT/p/3915221.html
Copyright © 2011-2022 走看看