Java 反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,,类的成员,我们在运行的时候还可以动态地去操作他们.

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

Class类说起

如果你使用Java,那么你应该知道Java中有一个Class类。Class类本身表示Java对象的类型,我们可以通过一个Object(子)对象的getClass方法取得一个对象的类型,此函数返回的就是一个Class类。当然,获得Class对象的方法有许多,但是没有一种方法是通过Class的构造函数来生成Class对象的。

也许你从来没有使用过Class类,也许你曾以为这是一个没什么用处的东西。不管你以前怎么认为,Class类是整个Java反射机制的源头。一切关于Java反射的故事,都从Class类开始。

因此,要想使用Java反射,我们首先得到Class类的对象。下表列出了几种得到Class类的方法,以供大家参考。

Class object 诞生管道

示例

运用getClass()

注:每个class 都有此函数

String str = "abc";

Class c1 = str.getClass();

运用

Class.getSuperclass()

Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

运用static method

Class.forName()

(最常被使用)

Class c1 = Class.forName ("java.lang.String");

Class c2 = Class.forName ("java.awt.Button");

Class c3 = Class.forName ("java.util.LinkedList$Entry");

Class c4 = Class.forName ("I");

Class c5 = Class.forName ("[I");

运用

.class 语法

Class c1 = String.class;

Class c2 = java.awt.Button.class;

Class c3 = Main.InnerClass.class;

Class c4 = int.class;

Class c5 = int[].class;

运用

primitive wrapper classes

的TYPE 语法

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;

获取一些基本信息

在我们得到一个类的Class类对象之后,Java反射机制就可以大施拳脚了。首先让我们来了解下如何获取关于某一个类的一些基本信息。

Java class 内部模块

Java class 内部模块说明

相应之Reflection API,多半为Class methods。

返回值类型(return type)

package

class隶属哪个package

getPackage()

Package

import

class导入哪些classes

无直接对应之API。可间接获取。

 

modifier

class(或methods, fields)的属性

int getModifiers()

Modifier.toString

(int)

Modifier.isInterface(int)

int

String

bool

class name or interface name

class/interface

名称getName()

String

type parameters

参数化类型的名称

getTypeParameters()

TypeVariable <Class>[]

base class

base class(只可能一个)

getSuperClass()

Class

implemented interfaces

实现有哪些interfaces

getInterfaces()

Class[]

inner classes

内部classes

getDeclaredClasses()

Class[]

outer class

如果我们观察的class 本身是inner classes,那么相对它就会有个outer class。

getDeclaringClass()

Class

上表中,列出了一些Java class内部信息的获取方式。所采用的方法几乎都是调用Class对象的成员方法(由此你就可以了解到Class类的用处了吧)。当然,表中所列出的信息并不是全部,有很大一部分没有列出,你可以通过查阅Java文档得到更全面的了解。另外,下面将重点介绍一下类的构造函数、域和成员方法的获取方式。

类中最重要的三个信息

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

也许你不同意我的排名,没关系。对于Java反射来说,这三个信息与之前介绍的基本信息相比较而言,有着本质的区别。那就是,之前的信息仅仅是只读的,而这三个信息可以在运行时被调用(构造函数和成员函数)或者被修改(成员变量)。所以,我想无可否认,至少站在Java反射机制的立场来说,这三者是最重要的信息。

下面,让我们分别了解一下这三个重要信息的获取方式。另外,我们将在后面的章节,详细介绍他们的调用方式或者修改方式。

构造函数

如果我们将Java对象视为一个二进制的生活在内存中生命体的话,那么构造函数无疑可以类比为Java对象生命体的诞生过程。我们在构造函数调用时为对象分配内存空间,初始化一些属性,于是一个新的生命诞生了。

Java是纯面向对象的语言,Java中几乎所有的一切都是类的对象,因此可想而知构造函数的重要性。

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

获取构造函数的方法有以下几个:

Constructor getConstructor(Class[] params) 

Constructor[] getConstructors()

Constructor getDeclaredConstructor(Class[] params) 

Constructor[] getDeclaredConstructors()

我们有两种方式对这四个函数分组。

首先可以由构造函数的确定性进行分类。我们知道,一个类实际上可以拥有很多个构造函数。那么我们获取的构造函数是哪个呢?我们可以根据构造函数的参数标签对构造函数进行明确的区分,因此,如果我们在Java反射时指定构造函数的参数,那么我们就能确定地返回我们需要的那个“唯一”的构造函数。getConstructor(Class[] params) 和getDeclaredConstructor(Class[] params)正是这种确定唯一性的方式。但是,如果我们不清楚每个构造函数的参数表,或者我们出于某种目的需要获取所有的构造函数的信息,那么我们就不需要明确指定参数表,而这时返回的就应该是构造函数数组,因为构造函数很可能不止一个。getConstructors()和getDeclaredConstructors()就是这种方式。

另外,我们还可以通过构造函数的访问权限进行分类。在设计类的时候,我们往往有一些构造函数需要声明为“private”、“protect”或者“default”,目的是为了不让外部的类调用此构造函数生成对象。于是,基于访问权限的不同,我们可以将构造函数分为public和非public两种。

getConstructor(Class[] params) getConstructors()仅仅可以获取到public的构造函数,而getDeclaredConstructor(Class[] params) getDeclaredConstructors()则能获取所有(包括public和非public)的构造函数。

成员函数

如果构造函数类比为对象的诞生过程的话,成员函数无疑可以类比为对象的生命行为过程。成员函数的调用执行才是绝大多数对象存在的证据和意义。Java反射机制允许获取成员函数(或者说成员方法)的信息,也就是说,反射机制能够帮助对象践行生命意义。通俗地说,Java反射能使对象完成其相应的功能。

和获取构造函数的方法类似,获取成员函数的方法有以下一些:

Method getMethod(String name, Class[] params)

Method[] getMethods()

Method getDeclaredMethod(String name, Class[] params) 

Method[] getDeclaredMethods() 

其中需要注意,String name参数,需要写入方法名。关于访问权限和确定性的问题,和构造函数基本一致。

成员变量

成员变量,我们经常叫做一个对象的域。从内存的角度来说,构造函数和成员函数都仅仅是Java对象的行为或过程,而成员变量则是真正构成对象本身的细胞和血肉。简单的说,就是成员变量占用的空间之和几乎就是对象占用的所有内存空间。

获取成员变量的方法与上面两种方法类似,具体如下:

Field getField(String name)

Field[] getFields()

Field getDeclaredField(String name)

Field[] getDeclaredFields()

其中,String name参数,需要写入变量名。关于访问权限和确定性的问题,与前面两例基本一致。

示例

1.package cn.lee.demo;  
2.  
3.import java.lang.reflect.Constructor;  
4.import java.lang.reflect.Field;  
5.import java.lang.reflect.InvocationTargetException;  
6.import java.lang.reflect.Method;  
7.import java.lang.reflect.Modifier;  
8.import java.lang.reflect.TypeVariable;  
9.  
10.public class Main {  
11.    /** 
12.     * 为了看清楚Java反射部分代码,所有异常我都最后抛出来给虚拟机处理! 
13.     * @param args 
14.     * @throws ClassNotFoundException 
15.     * @throws InstantiationException 
16.     * @throws IllegalAccessException 
17.     * @throws InvocationTargetException  
18.     * @throws IllegalArgumentException  
19.     * @throws NoSuchFieldException  
20.     * @throws SecurityException  
21.     * @throws NoSuchMethodException  
22.     */  
23.    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, NoSuchFieldException, NoSuchMethodException {  
24.        // TODO Auto-generated method stub  
25.          
26.        //Demo1.  通过Java反射机制得到类的包名和类名  
27.        Demo1();  
28.        System.out.println("===============================================");  
29.          
30.        //Demo2.  验证所有的类都是Class类的实例对象  
31.        Demo2();  
32.        System.out.println("===============================================");  
33.          
34.        //Demo3.  通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在],无参构造  
35.        Demo3();  
36.        System.out.println("===============================================");  
37.          
38.        //Demo4:  通过Java反射机制得到一个类的构造函数,并实现构造带参实例对象  
39.        Demo4();  
40.        System.out.println("===============================================");  
41.          
42.        //Demo5:  通过Java反射机制操作成员变量, set 和 get  
43.        Demo5();  
44.        System.out.println("===============================================");  
45.          
46.        //Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等  
47.        Demo6();  
48.        System.out.println("===============================================");  
49.          
50.        //Demo7: 通过Java反射机制调用类中方法  
51.        Demo7();  
52.        System.out.println("===============================================");  
53.          
54.        //Demo8: 通过Java反射机制获得类加载器  
55.        Demo8();  
56.        System.out.println("===============================================");  
57.          
58.    }  
59.      
60.    /** 
61.     * Demo1: 通过Java反射机制得到类的包名和类名 
62.     */  
63.    public static void Demo1()  
64.    {  
65.        Person person = new Person();  
66.        System.out.println("Demo1: 包名: " +
67.                    person.getClass().getPackage().getName() + ","   
68.                + "完整类名: " + person.getClass().getName());  
69.    }  
70.      
71.    /** 
72.     * Demo2: 验证所有的类都是Class类的实例对象 
73.     * @throws ClassNotFoundException  
74.     */  
75.    public static void Demo2() throws ClassNotFoundException  
76.    {  
77.        //定义两个类型都未知的Class , 设置初值为null, 看看如何给它们赋值成Person类  
78.        Class<?> class1 = null;  
79.        Class<?> class2 = null;  
80.          
81.        //写法1, 可能抛出 ClassNotFoundException [多用这个写法]  
82.        class1 = Class.forName("cn.lee.demo.Person");  
83.        System.out.println("Demo2:(写法1) 包名: " + class1.getPackage().getName() + ","   
84.                + "完整类名: " + class1.getName());  
85.          
86.        //写法2  
87.        class2 = Person.class;  
88.        System.out.println("Demo2:(写法2) 包名: " + class2.getPackage().getName() + ","   
89.                + "完整类名: " + class2.getName());  
90.    }  
91.      
92.    /** 
93.     * Demo3: 通过Java反射机制,用Class 创建类对象[这也就是反射存在的意义所在] 
94.     * @throws ClassNotFoundException  
95.     * @throws IllegalAccessException  
96.     * @throws InstantiationException  
97.     */  
98.    public static void Demo3() throws ClassNotFoundException, InstantiationException, IllegalAccessException  
99.    {  
100.        Class<?> class1 = null;  
101.        class1 = Class.forName("cn.lee.demo.Person");  
102.        //由于这里不能带参数,所以你要实例化的这个类Person,一定要有无参构造函数哈~  
103.        Person person = (Person) class1.newInstance();  
104.        person.setAge(20);  
105.        person.setName("LeeFeng");  
106.        System.out.println("Demo3: " + person.getName() + " : " + person.getAge());  
107.    }  
108.      
109.    /** 
110.     * Demo4: 通过Java反射机制得到一个类的构造函数,并实现创建带参实例对象 
111.     * @throws ClassNotFoundException  
112.     * @throws InvocationTargetException  
113.     * @throws IllegalAccessException  
114.     * @throws InstantiationException  
115.     * @throws IllegalArgumentException  
116.     */  
117.    public static void Demo4() throws ClassNotFoundException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException  
118.    {  
119.        Class<?> class1 = null;  
120.        Person person1 = null;  
121.        Person person2 = null;  
122.          
123.        class1 = Class.forName("cn.lee.demo.Person");  
124.        //得到一系列构造函数集合  
125.        Constructor<?>[] constructors = class1.getConstructors();  
126.          
127.        person1 = (Person) constructors[0].newInstance();  
128.        person1.setAge(30);  
129.        person1.setName("leeFeng");  
130.          
131.        person2 = (Person) constructors[1].newInstance(20,"leeFeng");  
132.          
133.        System.out.println("Demo4: " + person1.getName() + " : " + person1.getAge()  
134.                + "  ,   " + person2.getName() + " : " + person2.getAge()  
135.                );  
136.          
137.    }  
138.      
139.    /** 
140.     * Demo5: 通过Java反射机制操作成员变量, set 和 get 
141.     *  
142.     * @throws IllegalAccessException  
143.     * @throws IllegalArgumentException  
144.     * @throws NoSuchFieldException  
145.     * @throws SecurityException  
146.     * @throws InstantiationException  
147.     * @throws ClassNotFoundException  
148.     */  
149.    public static void Demo5() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException, InstantiationException, ClassNotFoundException  
150.    {  
151.        Class<?> class1 = null;  
152.        class1 = Class.forName("cn.lee.demo.Person");  
153.        Object obj = class1.newInstance();  
154.          
155.        Field personNameField = class1.getDeclaredField("name");  
156.        personNameField.setAccessible(true);  
157.        personNameField.set(obj, "胖虎先森");  
158.          
159.          
160.        System.out.println("Demo5: 修改属性之后得到属性变量的值:" + personNameField.get(obj));  
161.          
162.    }  
163.      
164.  
165.    /** 
166.     * Demo6: 通过Java反射机制得到类的一些属性: 继承的接口,父类,函数信息,成员信息,类型等 
167.     * @throws ClassNotFoundException  
168.     */  
169.    public static void Demo6() throws ClassNotFoundException  
170.    {  
171.        Class<?> class1 = null;  
172.        class1 = Class.forName("cn.lee.demo.SuperMan");  
173.          
174.        //取得父类名称  
175.        Class<?>  superClass = class1.getSuperclass();  
176.        System.out.println("Demo6:  SuperMan类的父类名: " + superClass.getName());  
177.          
178.        System.out.println("===============================================");  
179.          
180.          
181.        Field[] fields = class1.getDeclaredFields();  
182.        for (int i = 0; i < fields.length; i++) {  
183.            System.out.println("类中的成员: " + fields[i]);  
184.        }  
185.        System.out.println("===============================================");  
186.          
187.          
188.        //取得类方法  
189.        Method[] methods = class1.getDeclaredMethods();  
190.        for (int i = 0; i < methods.length; i++) {  
191.            System.out.println("Demo6,取得SuperMan类的方法:");  
192.            System.out.println("函数名:" + methods[i].getName());  
193.            System.out.println("函数返回类型:" + methods[i].getReturnType());  
194.            System.out.println("函数访问修饰符:" + Modifier.toString(methods[i].getModifiers()));  
195.            System.out.println("函数代码写法: " + methods[i]);  
196.        }  
197.          
198.        System.out.println("===============================================");  
199.          
200.        //取得类实现的接口,因为接口类也属于Class,所以得到接口中的方法也是一样的方法得到哈  
201.        Class<?> interfaces[] = class1.getInterfaces();  
202.        for (int i = 0; i < interfaces.length; i++) {  
203.            System.out.println("实现的接口类名: " + interfaces[i].getName() );  
204.        }  
205.          
206.    }  
207.      
208.    /** 
209.     * Demo7: 通过Java反射机制调用类方法 
210.     * @throws ClassNotFoundException  
211.     * @throws NoSuchMethodException  
212.     * @throws SecurityException  
213.     * @throws InvocationTargetException  
214.     * @throws IllegalAccessException  
215.     * @throws IllegalArgumentException  
216.     * @throws InstantiationException  
217.     */  
218.    public static void Demo7() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException  
219.    {  
220.        Class<?> class1 = null;  
221.        class1 = Class.forName("cn.lee.demo.SuperMan");  
222.          
223.        System.out.println("Demo7: \n调用无参方法fly():");  
224.        Method method = class1.getMethod("fly");  
225.        method.invoke(class1.newInstance());  
226.          
227.        System.out.println("调用有参方法walk(int m):");  
228.        method = class1.getMethod("walk",int.class);  
229.        method.invoke(class1.newInstance(),100);  
230.    }  
231.      
232.    /** 
233.     * Demo8: 通过Java反射机制得到类加载器信息 
234.     *  
235.     * 在java中有三种类类加载器。[这段资料网上截取] 
236. 
237.        1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。 
238. 
239.        2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类 
240. 
241.        3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。 
242.     *  
243.     * @throws ClassNotFoundException  
244.     */  
245.    public static void Demo8() throws ClassNotFoundException  
246.    {  
247.        Class<?> class1 = null;  
248.        class1 = Class.forName("cn.lee.demo.SuperMan");  
249.        String nameString = class1.getClassLoader().getClass().getName();  
250.          
251.        System.out.println("Demo8: 类加载器类名: " + nameString);  
252.    }  
253.      
254.      
255.      
256.}   
262.class  Person{  
263.    private int age;  
264.    private String name;  
265.    public Person(){  
266.          
267.    }  
268.    public Person(int age, String name){  
269.        this.age = age;  
270.        this.name = name;  
271.    }  
272.  
273.    public int getAge() {  
274.        return age;  
275.    }  
276.    public void setAge(int age) {  
277.        this.age = age;  
278.    }  
279.    public String getName() {  
280.        return name;  
281.    }  
282.    public void setName(String name) {  
283.        this.name = name;  
284.    }  
285.}  
286.  
287.class SuperMan extends Person implements ActionInterface  
288.{  
289.    private boolean BlueBriefs;  
290.      
291.    public void fly()  
292.    {  
293.        System.out.println("超人会飞耶~~");  
294.    }  
295.      
296.    public boolean isBlueBriefs() {  
297.        return BlueBriefs;  
298.    }  
299.    public void setBlueBriefs(boolean blueBriefs) {  
300.        BlueBriefs = blueBriefs;  
301.    }  
302.  
303.    @Override  
304.    public void walk(int m) {  
305.        // TODO Auto-generated method stub  
306.        System.out.println("超人会走耶~~走了" + m + "米就走不动了!");  
307.    }  
308.}  
309.interface ActionInterface{  
310.    public void walk(int m);  
311.}  

你可能感兴趣的:(java,反射机制)