Java动态程序设计 反射介绍 使用运行的类的信息使你的程序设计更加灵活反射授予了你的代码访问装载进JVM内的Java类的内部信息的权限 并且允许你编写在程序执行期间与所选择的类的一同工作的代码 而不是在源代码中 这种机制使得反射成为创建灵活的应用程序的强大工具 但是要小心的是 如果使用不恰当 反射会带来很大的副作用 在这篇文章中 软件咨询顾问Dennis Sosnoski 介绍了反射的使用 同时还介绍了一些使用反射所要付出的代价 在这里 你可以找到Java反射API是如何在运行时让你钩入对象的 在第一部分 我向你介绍了Java程序设计的类以及类的装载 那篇文章中描述了很多出现在Java二进制类格式中的信息 现在我来介绍在运行时使用反射API访问和使用这些信息的基础 为了使那些已经了解反射基础的开发人员对这些事情感兴趣 我还会介绍一些反射与直接访问的在性能方面的比较 使用反射与和metadata(描述其它数据的数据)一些工作的Java程序设计是不同的 通过Java语言反射来访问的元数据的特殊类型是在JVM内部的类和对象的描述 反射使你可以在运行时访问各种类信息 它甚至可以你让在运行时读写属性字段 调用所选择的类的方法 反射是一个强大的工具 它让你建立灵活能够在运行时组装的代码 而不需要连接组件间的源代码 反射的一些特征也带来一些问题 在这章中 我将会探究在应用程序中不打算使用反射的原因 以为什么使用它的原因 在你了解到这些利弊之后 你就会在好处大于缺点的时候做出决定 初识class 使用反射的起点总时一个java lang Class类的实例 如果你与一个预先确定的类一同工作 Java语言为直接获得Class类的实例提供了一个简单的快捷方式 例如 Class clas = MyClass class;当你使用这项技术的时候 所有与装载类有关的工作都发生在幕后 如果你需要在运行时从外部的资源中读取类名 使用上面这种方法是不会达到目的的 相反你需要使用类装载器来查找类的信息 方法如下所示 // name is the class name to loadClass clas = null;try {clas = Class forName(name);} catch (ClassNotFoundException ex) {// handle exception case}// use the loaded class如果类已经装载 你将会找到当前在在的类的信息 如果类还没有被装载 那么类装载器将会装载它 并且返回最近创建的类的实例 关于类的反射 Class对象给予你了所有的用于反射访问类的元数据的基本钩子 这些元数据包括有关类的自身信息 例如象类的包和子类 还有这个类所实现的接口 还包括这个类所定义的构造器 属性字段以及方法的详细信息 后面的这些项是我们在程序设计过种经常使用的 因此在这一节的后面我会给出一些用这些信息来工作的例子 对于类的构造中的每一种类型(构造器 属性字段 方法) java lang Class提供了四种独立的反射调用以不的方式来访问类的信息 下面列出了这四种调用的标准形式 它是一组用于查找构造器的调用 Constructor getConstructor(Class[] params) 使用指定的参数类型来获得公共的构造器 Constructor[] getConstructors()获得这个类的所有构造器 Constructor getDeclaredConstructor(Class[] params) 使用指定的参数类型来获得构造器(忽略访问的级别)Constructor[] getDeclaredConstructors() 获得这个类的所有的构造器(忽略访问的级别)上述的每一种方法都返回一或多个java lang reflect Constructor的实例 Constructor类定义了一个需要一个对象数据做为唯一参数的newInstance方法 然后返回一个最近创建的原始类的实例 对象数组是在构造器调用时所使用的参数值 例如 假设你有一个带有一对String 类型做为参数的构造器的TwoString类 代码如下所示 public class TwoString {private String m_s m_s ;public TwoString(String s String s ) {m_s = s ;m_s = s ;}}下面的代码显示如何获得TwoString类的构造器 并使用字符串 a 和 b 来创建一个实例 Class[] types = new Class[] { String class String class };Constructor cons = TwoString class getConstructor(types);Object[] args = new Object[] { a b };TwoString ts = cons newInstance(args);上面的代码忽略了几种可能的被不同的反射方法抛出的异常检查的类型 这些异常在Javadoc API中有详细的描述 因此为简便起见 我会在所有的代码中忽略它们 在我涉及到构造器这个主题时 Java语言也定义了一个特殊的没有参数的(或默认)构造器快捷方法 你能使用它来创建一个类的实例 这个快捷方法象下面的代码这样被嵌入到类的自定义中 Object newInstance() 使用默认的构造器创建新的实例 尽管这种方法只让你使用一个特殊的构造器 但是如果你需要的话 它是非常便利的快捷方式 这项技术在使用JavaBeans工作的时候尤其有用 因为JavaBeans需要定义一个公共的 没有参数的构造器 通过反射来查找属性字段 Class类反射调用访问属性字段信息与那些用于访问构造器的方法类似 在有数组类型的参数的使用属性字段名来替代 使用方法如下所示 Field getField(String name) 获得由name指定的具有public级别的属性字段Field getFields() 获得一个类的所有具有public级别的属性字段Field getDeclaredField(String name) 获得由name指定的被类声明的属性字段Field getDeclaredFields() 获得由类定义的所有的属性字段尽管与构造器的调用很相似 但是在提到属性字段的时候 有一个重要的差别 前两个方法返回能过类来访问的公共(public)属性字段的信息(包括那些来自于超类的属性字段) 后两个方法返回由类直接声明的所有的属性字段(忽略了属性字段的访问类型) Java lang reflect Field的实例通过调用定义好的getXXX和setXXX方法来返回所有的原始的数据类型 就像普通的与对象引用一起工作的get和set方法一样 尽管getXXX方法会自动地处理数据类型转换(例如使用getInt方法来获取一个byte类型的值) 但使用一个适当基于实际的属性字段类型的方法是应该优先考虑的 下面的代码显示了如何使用属性字段的反射方法 通过指定属性字段名 找到一个对象的int类型的属性字段 并给这个属性字段值加 public int incrementField(String name Object obj) throws {Field field = obj getClass() getDeclaredField(name);int value = field getInt(obj) + ;field setInt(obj value);return value;}这个方法开始展现一些使用反射所可能带来的灵活性 它优于与一个特定的类一同工作 incrementField方法把要查找的类信息的对象传递给getClass方法 然后直接在那个类中查找命名的属性字段 通过反射来查找方法 Class反射调用访问方法的信息与访问构造器和字段属性的方法非常相似 Method getMethod(String name Class[] params) 使用指定的参数类型获得由name参数指定的public类型的方法 Mehtod[] getMethods()获得一个类的所有的public类型的方法Mehtod getDeclaredMethod(String name Class[] params)使用指定的参数类型获得由name参数所指定的由这个类声明的方法 Method[] getDeclaredMethods() 获得这个类所声明的所有的方法与属性字段的调用一样 前两个方法返回通过这个类的实例可以访问的public类型的方法包括那些继承于超类的方法 后两个方法返回由这个类直接声明的方法的信息 而不管方法的访问类型 通过调用返回的Java lang reflect Mehtod实例定义了一个invoke方法 你可以使用它来调用定义类的有关实例 这个invoke方法需要两个参数 一个是提供这个方法的类的实例 一个是调用这个方法所需要的参数值的数组 下面给出了比属性字段的例子更加深入的例子 它显示了一个的方法反射的例子 这个方法使用get和set方法来给JavaBean定义的int类型的属性做增量 *** 作 例如 如果对象为一个整数类型count属性定义了getCount和setCount方法 那么为了给这个属性做增量运算 你就可以把 count 做为参数名传递给调用的这个方法中 示例代码如下 public int incrementProperty(String name Object obj) {String prop = Character toUpperCase(name charAt( )) +name substring( );String mname = get + prop;Class[] types = new Class[] {};Method method = obj getClass() getMethod(mname types);Object result = method invoke(obj new Object[ ]);int value = ((Integer)result) intValue() + ;mname = lishixinzhi/Article/program/Java/hx/201311/26154
谁说的?都说接口中的变量,常量,方法都是public static final????
变量被final了那还叫变量么?被final的都叫常量
确实,在接口中定义的属性是public static final
但是方法就不是,它只是public abstract型的,没有static和final
我刚写的,你自己运行一下看看
import javalangreflectMethod;
public class Refect {
public static void main(String[] args) {
Class a=BaiDuclass;
Method[] method=agetDeclaredMethods();
for(int i=0;i<methodlength;i++){
Systemoutprintln(method[i]);
}
}
}
interface BaiDu{
String a="2";
void add();
}
反射就是把Java的各种成分映射成相应的Java类。
Class类的构造方法是private,由JVM创建。
反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行 *** 作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。(来自Sun)
JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的 *** 作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
反射是从12就有的,后面的三大框架都会用到反射机制,涉及到类"Class",无法直接new CLass(),其对象是内存里的一份字节码
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
基本的 Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。Class 没有公共构造方法。
Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
Person p1 = new Person();
//下面的这三种方式都可以得到字节码
CLass c1 = Dateclass();
p1getClass();
//若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来
ClassforName("javalangString");
ClassforName()字节码已经加载到java虚拟机中,去得到字节码;java虚拟机中还没有生成字节码 用类加载器进行加载,加载的字节码缓冲到虚拟机中。
另外,大家可以关注微信公众号Java技术栈回复:JVM,获取我整理的系列JVM教程,都是干货。
考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。
import javalangreflect;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = ClassforName("javautilStack");
Method m[] = cgetDeclaredMethods();
for (int i = 0; i < mlength; i++)
Systemoutprintln(m[i]toString());
}
catch (Throwable e){
Systemerrprintln(e);
}
}
}
public synchronized javalangObject javautilStackpop()
public javalangObject javautilStackpush(javalangObject)
public boolean javautilStackempty()
public synchronized javalangObject javautilStackpeek()
public synchronized int javautilStacksearch(javalangObject)
这样就列出了javautilStack 类的各方法名以及它们的限制符和返回类型。这个程序使用 ClassforName 载入指定的类,然后调用 getDeclaredMethods 来获取这个类中定义了的方法列表。javalangreflectMethods 是用来描述某个类中单个方法的一个类。
以下示例使用 Class 对象来显示对象的类名:
void printClassName(Object obj) {
Systemoutprintln("The class of " + obj +
" is " + objgetClass()getName());
}
还可以使用一个类字面值(JLS Section 1582)来获取指定类型(或 void)的 Class 对象。例如:
Systemoutprintln("The name of class Foo is: "+FooclassgetName());
在没有对象实例的时候,主要有两种办法。
//获得类类型的两种方式
Class cls1 = Roleclass;
Class cls2 = ClassforName("yuiRole");
注意第二种方式中,forName中的参数一定是完整的类名(包名+类名),并且这个方法需要捕获异常。现在得到cls1就可以创建一个Role类的实例了,利用Class的newInstance方法相当于调用类的默认的构造器。
Object o = cls1newInstance();
//创建一个实例
//Object o1 = new Role(); //与上面的方法等价
首先,请您先理解一下反射的基本原理否则我下述的代码您可能有点摸不着头脑
反射是NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外还可以直接创建对象,即使这个对象的类型在编译时还不知道。
反射的基本过程如下,请您务必阅读完毕后我将给你写出对应的代码
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
第一种:通过forName()方法;
第二种:类class;
第三种:对象getClass()。
举例如下:
package
test;
public class Demo{
public static void
main(){
Class<> c1 = null;
Class<> c2 =
null;
Class<> c3 =
null;
//三种反射用实例化方式
try{
//最常用的一种形式
c1 =
ClassforName("testX");
}catch(ClassNotFoundException
e){
eprintStackTrace();
}
//通过Object类中的方法实例化
c2
= new X()getClass();
//通过类class实例化
c3 =
Xclass;
Systemoutprintln("类名:" + c1getName());
//得到类名
Systemoutprintln("类名:" + c2getName());
//得到类名
Systemoutprintln("类名:" + c3getName());
//得到类名
}
}
可以实现,很方便。我去找个例子贴给你
Class daoFactoryClass = ClassforName(daoName);
//daoName是DAOFactory实现类的名字
// types of the constructor arguments
Class[] constrArgs = {Propertiesclass};
Object[] args = {daoProps};
//daoProps是Properties类型,它的内容来自一个配置文件
// get Constructor of this class with matching parameter types
Constructor<IDAOFactory> constructor = daoFactoryClassgetConstructor(constrArgs);
thisfactory = constructornewInstance(args);
以上就是关于Java动态程序设计——反射介绍全部的内容,包括:Java动态程序设计——反射介绍、java反射获取接口修饰符、java反射机制详解等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)