Java反射:(很重要,也很难)
在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的功能来自于Java语言的反射机制(Reflection)
——————
Java的反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法。
(注意!!都是在运行时)
————————————
Reflection是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public static等等),superclass(诸如Object),实现interfaces(例如Serializable),也包括fields和methods的所有信息,并可于运行时改变fileds内容或者调用methods。
——————
一般而言,开发者社群说到动态语言时,大致认同的一个定义是:程序运行时,允许改变程序结构或变量类型,这种语言被称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。
尽管在这样的定义与分类下Java不是动态语言,它却有一个非常突出的动态相关机制:Reflection。这个字的意思是“反射,映像,倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体,或对其fields设值,或唤起methods。这种“看透class”的能力(the ability of the progeam to examine itself)被称为introspection(内省,内观,反省)Reflection和introspection是常被并提的两个术语。
——————————
在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中。(除了Class类)
—Class类:代表一个类(位于java.lang下)
—Field类:代表类的成员变量(成员变量也被称为类的属性
)
–Method类:代表类的方法
–Constructor类:代表类的构造方法
–Array类:提供了动态创建数组,以及访问数组元素的静态方法。
——————————————————
Java中,无论生成某个类多少个对象,这些对象都会对应于同一个Class对象。
————
实例 DumpMethods类演示了Reflection API的基本作用,它读取指定的类名,然后打印这个类所具有的方法信息。
import java.lang.reflect.Method;
public class DumpMethods
{
public static void main(String[] args) throws ClassNotFoundException
{
//反射的第一步是获得待操作的类所对应的Class对象。
Class
package com.reflection;
/*
* 使用反射机制调用对象的私有方法,访问对象的私有成员变量
* 这时会破坏类的封装性,在开发中并不建议过多使用,因为这违反了面向对象设计原则
* 但是在某些情况下,我们必须要去调用某些私有方法,这时就必须使用反射来完成
*/
public class Private
{
private String sayHello(String name)
{
return "hello:"+name;
}
}
————————————————————
//实例
package com.reflection;
import java.lang.reflect.Method;
/*
* 新建一个类,完成对另一个类里私有方法的调用
* 要想去调用前一个类的方法,就必须先生成它的对象
*/
public class TestPrivate
{
public static void main(String[] args) throws Exception
{
//因为我们的关注点在如何调用方法。所以此处我们用new的方法生成对象,当然也可以使用反射
Private p=new Private();
//要想操纵方法,要先获得Class对象
Class<?> classType=p.getClass();
//获得Method对象,不能用getMethod(),因为其只能返回public方法
//要使用getDeclaredMethod()方法,它不要求返回public类型,这API都明确指出了的
Method method=classType.getDeclaredMethod("sayHelo", new Class[]{String.class});
//方法访问之前用setAccessible(true)设置java不进行类型检查
method.setAccessible(true);//压制Java的访问控制检查
//调用,返回一个字符串
String str=(String)method.invoke(p, new Object[]{"zhangsan"});
System.out.println(str);
}
}