Java反照应用示例

Java反射应用示例

一、预先需要掌握的知识(java虚拟机)

java虚拟机的方法区:

java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class中的类型信息,将这些信息存储到方法区中。这些信息主要包括:

1、这个类型的全限定名

2、这个类型的直接超类的全限定名

3、这个类型是类类型还是接口类型

4、这个类型的访问修饰符

5、任何直接超接口的全限定名的有序列表

6、该类型的常量池

7、字段信息

8、方法信息

9、除了常量以外的所有类变量

10、一个到class类的引用

等等(读者可以参考《深入java虚拟机》这本书的叙述)

Class类:

Class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例,该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过Class实例来访问这些信息。比如,对于上面说到的信息Class中都有对应的方法,如下:

1、getName();这个类型的全限定名

2、getSuperClass();这个类型的直接超类的全限定名

3、isInterface();这个类型是类类型还是接口类型

4、getTypeParamters();这个类型的访问修饰符

5、getInterfaces();任何直接超接口的全限定名的有序列表

6、getFields();字段信息

7、getMethods();方法信息

等等(读者可以自己参看jdk帮助文档,得到更多的信息)

 

二、java反射详解

反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到JVM中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。

 

反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class类中针对这三个元素的方法:

1、得到构造器的方法

Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,

Constructor[] getConstructors() -- 获得类的所有公共构造函数

Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)

Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)

2、获得字段信息的方法

Field getField(String name) -- 获得命名的公共字段

Field[] getFields() -- 获得类的所有公共字段

Field getDeclaredField(String name) -- 获得类声明的命名的字段

Field[] getDeclaredFields() -- 获得类声明的所有字段
3、获得方法信息的方法

Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法

Method[] getMethods() -- 获得类的所有公共方法

Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法

Method[] getDeclaredMethods() -- 获得类声明的所有方法

应用反射的基本步骤:

1、获得你想操作的类的Class对象;

     方法一:Class c=Class.forName("java.lang.String")

     方法二:对于基本数据类型可以用形如Class c=int.class或Class c=Integer.TYPE的语句

     方法三:Class c=MyClass.class

2、调用Class中的方法得到你想得到的信息集合,如调用getDeclaredFields()方法得到类的所有属性;

3、处理第2步中得到的信息,然后进行你想做的实际操作。

 

反射实例:

下面我将针对类的构造器、属性和方法分别举三个例子,向大家演示一下反射的应用过程。

1、构造器

步骤为:通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例

 

package com.test.reflect;

import java.lang.reflect.Constructor;

public class ConstructorDemo { 
	 
	public ConstructorDemo(){  
    }  
    public ConstructorDemo(int a, int b){  
        System.out.println("a="+a+"b="+b);  
    }  
      
    public static void main(String args[]){  
        try {  
            Class cls = Class.forName("com.test.reflect.ConstructorDemo");
         
            System.out.println("class类名称:"+cls.getName());
            Class partypes[] = new Class[2];  
            partypes[0] = Integer.TYPE;  
            partypes[1] = Integer.TYPE;  
              
            Constructor ct= cls.getConstructor(partypes);  
            Constructor[] c=cls.getConstructors();
            Object arglist[] = new Object[2];  
            arglist[0] = new Integer(37);  
            arglist[1] = new Integer(47);  
            Object retobj = ct.newInstance(arglist); 
            System.out.println("特定构造器对象:"+retobj); 
        }  
        catch (Throwable e) {  
            System.err.println(e);  
        }  
    }  

}

 

2、字段属性

步骤为:通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值

package com.test.reflect;

import java.lang.reflect.Field;


public class FieldDemo {
	public int a=7;
	public int d=9;
	private int b=12;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
	try {
			Class cls=Class.forName("com.test.reflect.FieldDemo");
			//public类型属性
			Field f=cls.getField("a"); 
			System.out.println("特定属性:"+f);
			Field[] fd= cls.getFields();
			System.out.println("所有public类型属性"+fd.length);
			//所有级别属性
			Field fld=cls.getDeclaredField("b");
			System.out.println("private类型属性:"+fld);
			Field[] fldd= cls.getDeclaredFields();
			System.out.println("所有类型属性"+fldd.length);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

 

3、方法

步骤为:通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

 

package com.test.reflect;

import java.lang.reflect.Method;

public class MethodDemo {
    public int add(int a, int b){  
        return a + b;  
    }  
	public static void main(String args[]) {

		try {
			Class cls = Class.forName("com.test.reflect.MethodDemo");
			Class partypes[] = new Class[2];
			partypes[0] = Integer.TYPE;
			partypes[1] = Integer.TYPE;

			Method meth = cls.getMethod("add", partypes);
			MethodDemo methobj = new MethodDemo();

			Object arglist[] = new Object[2];
			arglist[0] = new Integer(37);
			arglist[1] = new Integer(47);

			Object retobj = meth.invoke(methobj, arglist);
			Integer retval = (Integer) retobj;
			System.out.println(retval.intValue());
		} catch (Throwable e) {
			System.err.println(e);
		}
	}
}