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);
            }
        }
    
    }

    结果为:

    结果

    知识重在总结和梳理,只有不断地去学习并运用,才能化为自己的东西。由于本人进阶猿类时间尚短,故此博客即是我学习,工作的笔记,也是和大家交流,相互提升技术的平台~希望大家不吝赐教~~ --但管努力,莫问前程,事在人为,功不唐捐。--和佑博客园
  • 相关阅读:
    HDU 2433 Travel (最短路,BFS,变形)
    HDU 2544 最短路 (最短路,spfa)
    HDU 2063 过山车 (最大匹配,匈牙利算法)
    HDU 1150 Machine Schedule (最小覆盖,匈牙利算法)
    290 Word Pattern 单词模式
    289 Game of Life 生命的游戏
    287 Find the Duplicate Number 寻找重复数
    283 Move Zeroes 移动零
    282 Expression Add Operators 给表达式添加运算符
    279 Perfect Squares 完美平方数
  • 原文地址:https://www.cnblogs.com/XHJT/p/3915221.html
Copyright © 2011-2022 走看看