• 热门专题

Class类与反射机制初步(理论篇)

作者:MySpace  发布日期:2013-08-02 09:07:14
Tag标签:Class类  反射机制  
  •    今天课上学习了反射的一部分知识,反射机制是面向对象编程的一个重要的机制,这种思想值得我们深入学习和使用,于是课下我查找了好多相关知识的文档学习和总结,写下了这篇文章与大家分享,如果有不对的地方,我欣然接受大家指出的错误,并加以纠正。


       在学习反射之前首先介绍Class类:
    (1)如果你使用Java,那么你应该知道Java中有一个Class类。Class类本身表示Java对象的类型,我们可以通过一个Object对象的getClass方法取得一个对象的类型,此函数返回的就是一个Class类
    (2)Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
    (3)基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象
    (4)重要方法:forName(String className)返回与带有给定字符串名的类或接口相关联的 Class 对象。
    (5)Class类是整个Java反射机制的源头。一切关于Java反射的故事,都从Class类开始,因此,要想使用Java反射,我们首先得到Class类的对象。
    (6)如下列出几种得到Class类的方法:
    1.getClass()


    package day0801; 
    public class reflection { 
        public static void main(String[] args) { 
            String str="abc"; 
            Class c1=str.getClass(); 
            System.out.println(c1); 
        } 
    }

       输出结果:class java.lang.String

    2.getSuperClass()


    package day0801; 
    import java.awt.Button; 
    public class reflection { 
        public static void main(String[] args) { 
            Button b=new Button(); 
            Class c2=b.getClass(); 
            Class c3=c2.getSuperclass(); 
            System.out.println(c2); 
            System.out.println(c3); 
        } 
    }

       输出结果:class java.awt.Button

                 class java.awt.Component
       (Component是Button的父类)

    3.(static)forName()


    package day0801; 
    public class reflection { 
        public static void main(String[] args) throws ClassNotFoundException { 
            //使用forName时需指定参数:包名.类名 
            Class c1 = Class.forName ("java.lang.String"); 
            Class c2 = Class.forName ("java.awt.Button"); 
            Class c3 = Class.forName ("java.util.LinkedList$Entry"); 
            System.out.println(c1); 
            System.out.println(c2); 
            System.out.println(c3); 
        } 
    }

       输出结果:class java.lang.String

                 class java.awt.Button

                 class java.util.LinkedList$Entry

    4.语法.class


    package day0801; 
    public class reflection { 
        public static void main(String[] args) throws ClassNotFoundException { 
            Class c1 = String.class; 
            Class c2 = java.awt.Button.class; 
            Class c4 = int.class; 
            Class c5 = int[].class; 
            System.out.println(c1); 
            System.out.println(c2); 
            System.out.println(c4); 
            System.out.println(c5); 
        } 
    }

    输出结果:

     

    class java.lang.String 
    class java.awt.Button 
    int
    class [I

    5.使用原始包装类的TYPE语法

     

    package day0801; 
    public class reflection { 
        public static void main(String[] args) throws ClassNotFoundException { 
            Class c1 = Boolean.TYPE; 
            Class c2 = Byte.TYPE; 
            Class c3 = Character.TYPE; 
            Class c4 = Short.TYPE; 
            Class c5 = Integer.TYPE; 
            Class c6 = Long.TYPE; 
            Class c7 = Float.TYPE; 
            Class c8 = Double.TYPE; 
            Class c9 = Void.TYPE; 
            System.out.println(c1); 
            System.out.println(c2); 
            System.out.println(c3); 
            System.out.println(c4); 
            System.out.println(c5); 
            System.out.println(c6); 
            System.out.println(c7); 
            System.out.println(c8); 
            System.out.println(c9); 
        } 
    }

    输出结果:

     

    boolean
    byte
    char
    short
    int
    long
    float
    double
    void

       类中三个重要的信息
       如果要对一个类的信息重要性进行排名的话,那么这三个信息理应获得前三的名次。它们分别是:构造函数、成员函数、成员变量。
     
    1.构造方法

       Java反射机制能够得到构造函数信息实在应该是一件令人惊喜的事情。正因为此,反射机制实质上才拥有了孵化生命的能力。换句话言之,我们可以通过反射机制,动态地创建新的对象。
       获取构造函数的方法有以下几个:


       Constructor getConstructor(Class[] params)
       Constructor[] getConstructors()
       Constructor getDeclaredConstructor(Class[] params)
       Constructor[] getDeclaredConstructors()
       接下来我们通过对这四个函数的两种不同方式的分类来进行讲解:

     

    (1)按照构造函数的确定性分:
       如果我们在Java反射时指定构造函数的参数而确定地返回我们需要的那个“唯一”的构造函数,则用getConstructor(Class[] params) 和getDeclaredConstructor(Class[] params方式。
       相反,如果我们不清楚每个构造函数的参数表,或者我们出于某种目的需要获取所有的构造函数的信息,那么我们就不需要明确指定参数表,而这时返回的就应该是构造函数数组,因为构造函数很可能不止一个。getConstructors()和getDeclaredConstructors()就是这种方式。


    (2)按照构造函数的访问权限分:
       在设计类的时候,我们往往有一些构造函数需要声明为“private”、“protect”或者“default”,目的是为了不让外部的类调用此构造函数生成对象。于是,基于访问权限的不同,我们可以将构造函数分为public和非public两种。
       getConstructor(Class[] params) 和getConstructors()仅仅可以获取到public的构造函数,而getDeclaredConstructor(Class[] params) 和getDeclaredConstructors()则能获取所有(包括public和非public)的构造函数。


    2.成员函数

       如果构造函数类比为对象的诞生过程的话,成员函数无疑可以类比为对象的生命行为过程。成员函数的调用执行才是绝大多数对象存在的证据和意义。Java反射机制允许获取成员函数(或者说成员方法)的信息,也就是说,反射机制能够帮助对象践行生命意义。通俗地说,Java反射能使对象完成其相应的功能。
       和获取构造函数的方法类似,获取成员函数的方法有以下一些:
       Method getMethod(String name, Class[] params)
       Method[] getMethods()
       Method getDeclaredMethod(String name, Class[] params)
       Method[] getDeclaredMethods()
    (1)其中需要注意,String name参数,需要写入方法名。
    (2)关于访问权限和确定性的问题,和构造函数基本一致。


    3.成员属性

       从内存的角度来说,构造函数和成员函数都仅仅是Java对象的行为或过程,而成员变量则是真正构成对象本身的细胞和血肉。简单的说,就是成员变量占用的空间之和几乎就是对象占用的所有内存空间。
       获取成员变量的方法与上面两种方法类似,具体如下:
       Field getField(String name)
       Field[] getFields()
       Field getDeclaredField(String name)
       Field[] getDeclaredFields()
    (1)其中,String name参数,需要写入变量名。
    (2)关于访问权限和确定性的问题,与前面两例基本一致。

     


       java的反射机制初步
       Java反射机制是Java语言被视为准动态语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息(包括上面说的构造函数、成员函数、成员变量),动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
       下面,让我们就分别了解一下这三个重要信息的获取方式。
         使用下面这几个重要的方法:

    (1)Constructor的方法:
        newInstance(Object initargs)
        使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。


    (2)Method的方法:
        invoke(Object obj, Object args)
        对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
       说明:


       我们能很好理解此函数的第二个参数args,它代表这个方法所需要接收的参数。也许大家对第一个参数receiver还存在疑惑之处。这得从编程语言的发展历程讲起。
       如果你关注几种主流编程语言的起源,那么你能有这样的印象:C从汇编而来,C++从C而来,而Java从C/C++而来。有这样一种印象就足够了。从这样的发展史我们可以看出,C++和Java这两种面向对象的编程语言都是从面向过程的C语言基础上发展而来的。OOP是一种思想,它本身与编程语言无关。也就是说,我们用C也能写出面向对象的程序,这也是C++和Java能够以C为基础的根本所在。然而,C无法实现类似object.method()这种表现形式,因为C语言的结构体中并不支持函数定义。那么我们用C实现OOP的时候,如何调用对象的方法呢?
    本质上说,object.method()这种调用方式是为了表明具体method()的调用对象。而invoke(Object receiver, Object... args)的第一个参数正是指明调用对象。在C++中,object.method()其实是有隐含参数的,那就是object对象的指针,method原型的第一个参数其实是this指针,于是原型为method(void* this)。
       另外需要注意的是,如果某个方法是另外需要注意的是,如果某个方法是Java类的静态方法,那么Object receiver参数可以传入null,因为静态方法不从属于对象。

     


    (3)Field的方法:
        get(Object obj)
        返回指定对象上此 Field 表示的字段的值。
        set(Object obj,Object value)
        将指定对象变量上此 Field 对象表示的字段设置为指定的新值。


About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规