Class对象与反射机制的学习

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Class对象与反射机制的学习相关的知识,希望对你有一定的参考价值。

刚对java反射机制进行了学习,在此做一个总结。

总结分为三部分,一.介绍java的Class类概念,二.进一步介绍通过Class类我们可以获取关于类的哪些信息,三.反射方法的基本操作

在这之前,我们的脑海中一定要牢记如下一句话:“万物皆对象!” 这句话可以贯穿本节始终,帮助我们站在一个高度理解这部分内容。

一.java的Class类概念

  万物皆对象,那么对于面向对象语言java,我们就可以自然补充出下一句,万物皆有类,因为每个对象实例都有他所属于的类别。

  那么对于我们代码中的String, Date,Time类型也好,还是我们自定义的Demo等类也好,这些类换个角度来看也是一种对象,而这些特殊对象所隶属的类别就是Class类。(注:全路径为java.lang.Class)

  Class类实例化的对象即类对象,java中为每个类都定义了其独有的类对象,类对象包含了该类的一些信息和操作方法。

    在这里区分两个概念,“类对象”和“类的对象”,我们本章研究的是前者,拿String类举例子来说明:

  

String str = "abc"; //str是String的“类的对象”
Class c = String.class; //c是String的“类对象”

  明确了类对象的概念之后,介绍一下我们如何获取类对象。我们在包com.classtest下建立一个类DemoTest,那么有三种方法可以获得其类对象。

  

        //获取类对象的第一种方式(通过类)
        Class c1 = DemoTest.class;
        //获取类对象的第二种方式(通过类实例)
        DemoTest dt = new DemoTest();
        Class c2 = dt.getClass();
        
        //获取类类型的第三种方式(需要捕获异常),能够动态加载类的核心方法
        Class c3 = null;
        try{
            c3 = Class.forName("com.classtest.DemoTest");
        }catch(ClassNotFoundException e){
            e.printStackTrace();
        }            

   这里要特别指出的是,采用前两种方法,java在编译时就需要检测DemoTest类已经存在,否则编译错误,而第三种获得类对象的方法,只有在运行时才会判断使用的com.classtest.DemoTest类是否存在,否则报错,也因此需要加上异常判断。注意由于在运行时才判断获得哪个类的类对象,因此第三种方法是实现动态加载类的核心方法。

二.通过Class类对象我们可以获得的信息

  如果我们获得了一个类的类对象,那么我们就可以利用它获得此类的实例,类的类名,此类包含的方法名,此类的成员变量,此类的构造函数等丰富的信息。下面逐一说明。

  1)根据类的类对象获得该类的实例

    

    try{
      //调用类对象的newInstance()方法,获得实例dt1,注意需要强制类型转换
            DemoTest dt1 = (DemoTest)c3.newInstance();
            dt1.show();
      //注意捕获异常 }
catch(InstantiationException e){ e.printStackTrace(); }catch(IllegalAccessException e){ e.printStackTrace(); }

  2)根据类对象获得该类的类名

    

//调用类对象的getName方法
Class c = DemoTest.class;
String className = c.getName());

  3)根据类对象获得该类的方法

     万物皆对象,方法也是对象,其所属的类型为 java.lang.reflect.Method

     此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的方法

/*
     * 打印类的名称,类的方法信息
     * 方法也是一种对象,方法对象的类是java.lang.reflect.Method
     * @param ob 所测试类的对象
     */
    public static void getClassMethods(Object ob){
        Class c = ob.getClass();
     //类对象的getMethods方法返回 类包含方法对象的数组 Method[] methods
= c.getMethods(); System.out.println("当前类的类名为:"+c.getName()); System.out.println("类公开方法有:"); for(int i=0;i<methods.length;i++){ //得到方法的名称 System.out.print(methods[i].getName()+"("); //得到方法的参数名称 Class[] paramTypes = methods[i].getParameterTypes(); for(Class pt:paramTypes){ System.out.print(pt.getName()+","); } System.out.println(")"); } }

  4)根据类对象获得该类包含的成员变量

     万物皆对象,成员变量也是对象,其所属的类型为 java.lang.reflect.Field

     此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的成员变量

/*
     * 打印类的成员变量
     * 成员变量也是对象,属于java.lang.reflect.Fild类
     * Fild类封装了关于成员变量的操作
     * @param ob
     */
    public static void getClassField(Object ob){
        Class c = ob.getClass();
     //getFile返回类的成员变量对象数据
//Field[] fields = c.getFields(); Field[] fields = c.getDeclaredFields(); System.out.println("当前类的类名为:"+c.getName()); System.out.println("类的成员变量有:"); for(Field field:fields){ //获取成员变量的类类型 Class ftype = field.getType(); String className = ftype.getName(); String fieldName = field.getName(); System.out.println(className+" "+fieldName); } }

   5)根据类对象获取对应类的构造方法

      万物皆对象,构造方法也是对象,其所属的类型为 java.lang.reflect.Constructor

        此处定义了一个静态方法,参数为一个对象,返回了该对象所属类所包含的构造方法

/*
     * 获取类的所有构造函数的信息
     * 构造函数也是对象,构造函数属于类java.lang.reflect.Constructor
     * @param ob
     */
    public static void getConstructors(Object ob){
        Class c = ob.getClass();
        Constructor[] cons = c.getDeclaredConstructors();
        System.out.println("当前类的类名为:"+c.getName());
        System.out.println("类的构造方法有:");
        for(int i=0;i<cons.length;i++){
            //得到方法的名称
            System.out.print(cons[i].getName()+"(");
            //得到方法的参数名称
            Class[] paramTypes = cons[i].getParameterTypes();
            for(Class pt:paramTypes){
                System.out.print(pt.getName()+",");
            }
            System.out.println(")");
        }
    }

 三.方法反射的基本操作

  第二部分可以看出通过类对象我们可以获得关于类的一系列信息,本部分我们介绍通过获取的方法对象信息来反射调用类的方法。

  反射这里涉及两个问题1.如何获取特定的方法对象2.通过方法对象如何调用类的方法。

  1.获取特定的方法对象

  首先我们在自定义类型DemoTest类中定义两个方法。

  

  //定义一个无参方法show
  public void show(){
        System.out.println("this is a DemoTest");
    }
    //定义一个有参方法add
    public int add(int a,int b){
        return a+b;
    }

  然后获得该类的类对象,类对象有方法getMethod可以获得指定的方法对象,如下代码所示:

Class c = DemoTest.class
//获得无参方法show
Method m1 = c.getMethod("show");
//获得有参方法add
Method m2 = c.getMethod("add", int.class,int.class);

  2.通过方法对象调用方法,方法对象的invoke方法可以调用对应的方法,注意获取方法对象和调用均有可能抛出异常,因此合并写为如下代码:

try {
       Class c = DemoTest.class;            
       //获得无参方法show
            Method m1 = c.getMethod("show");
            //获得有参方法add
            Method m2 = c.getMethod("add", int.class,int.class);
            DemoTest demoTest = new DemoTest();
            //invoke方法来调用,需要传一个实例demoTest
            m1.invoke(demoTest);
            Object result = m2.invoke(demoTest, 2,3);
            System.out.println(result);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }            

这样就完成了通过方法对象反射调用对应的方法。

自己的理解:程序员通过类对象,方法对象,成员变量对象,构造方法对象等进行程序操作的行为,相对于类,方法,成员变量,构造方法来说,就是反射操作。反射操作已经跳过了java代码,而类似是在直接操作编译后的.class代码,因此反射相关的程序可以动态加载一些资源,仅仅当运行期会查找使用资源是否存在且合理,而报出错误。

以上是关于Class对象与反射机制的学习的主要内容,如果未能解决你的问题,请参考以下文章

Java学习注解和反射超详细笔记

Java Demo 学习 理解 反射机制 (基础学习)

请问java中的反射机制与用法

类加载机制与反射

反射机制

Java学习十三