java反射机制详解_java反射机制原理详解
反射机制:所谓的反射机制就是java语⾔在运⾏时拥有⼀项⾃观的能⼒。通过这种能⼒可以彻底的了解⾃⾝的情况为下⼀步的动作做准备。下⾯具体介绍⼀下java的反射机制。这⾥你将颠覆原来对java的理解。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;其中class代表的时类对
象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的⽅法对象。通过这四个对象我们可以粗略的看到⼀个类的各个组
成部分。
Class:程序运⾏时,java运⾏时系统会对所有的对象进⾏运⾏时类型的处理。这项信息记录了每个对象所属的类,虚拟机通常使⽤运⾏时类型信息选择正
确的⽅法来执⾏(摘⾃:⽩⽪书)。但是这些信息我们怎么得到啊,就要借助于class类对象了啊。在Object类中定义了getClass()⽅法。我
们可以通过这个⽅法获得指定对象的类对象。然后我们通过分析这个对象就可以得到我们要的信息了。
⽐如:ArrayList arrayList;
Class clazz = Class();
然后我来处理这个对象clazz。
当然了Class类具有很多的⽅法,这⾥重点将和Constructor,Field,Method类有关系的⽅法。
Reflection 是 Java 程序开发语⾔的特征之⼀,它允许运⾏中的 Java
程序对⾃⾝进⾏检查,或者说“⾃审”,并能直接操作程序的内部属性。Java
的这⼀能⼒在实际应⽤中也许⽤得不是很多,但是个⼈认为要想对java有个更加深⼊的了解还是应该掌握的。
1.检测类:
reflection的⼯作机制
考虑下⾯这个简单的例⼦,让我们看看 reflection 是如何⼯作的。
import flect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
}
}
}
按如下语句执⾏:
java DumpMethods java.util.ArrayList
这个程序使⽤ Class.forName 载⼊指定的类,然后调⽤ getDeclaredMethods
来获取这个类中定义了的⽅法列表。flect.Methods 是⽤来描述某个类中单个⽅法的⼀个类。
Java类反射中的主要⽅法
对于以下三类组件中的任何⼀类来说 -- 构造函数、字段和⽅法 -- java.lang.Class
提供四种独⽴的反射调⽤,以不同的⽅式来获得信息。调⽤都遵循⼀种标准格式。以下是⽤于查构造函数的⼀组反射调⽤:Constructor getConstructor(Class[] params) --
获得使⽤特殊的参数类型的公共构造函数,
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) --
获得使⽤特定参数类型的构造函数(与接⼊级别⽆关)
Constructor[] getDeclaredConstructors() --
获得类的所有构造函数(与接⼊级别⽆关)
获得字段信息的Class 反射调⽤不同于那些⽤于接⼊构造函数的调⽤,在参数类型数组中使⽤了字段名:
Field getField(String name) -- 获得命名的公共字段
Field[] getFields() -- 获得类的所有公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
Field[] getDeclaredFields() -- 获得类声明的所有字段
⽤于获得⽅法信息函数:
Method getMethod(String name, Class[] params) --
使⽤特定的参数类型,获得命名的公共⽅法
Method[] getMethods() -- 获得类的所有公共⽅法
Method getDeclaredMethod(String name, Class[] params) --
使⽤特写的参数类型,获得类声明的命名的⽅法
Method[] getDeclaredMethods() -- 获得类声明的所有⽅法
使⽤ Reflection:
⽤于 reflection 的类,如 Method,可以在 lfect
包中到。使⽤这些类的时候必须要遵循三个步骤:第⼀步是获得你想操作的类的 java.lang.Class 对象。在运⾏中的 Java 程序中,⽤ java.lang.Class 类来描述类和接⼝等。
下⾯就是获得⼀个 Class 对象的⽅法之⼀:
Class c = Class.forName("java.lang.String");
这条语句得到⼀个 String 类的类对象。还有另⼀种⽅法,如下⾯的语句:
Class c = int.class;
或者
Class c = Integer.TYPE;
它们可获得基本类型的类信息。其中后⼀种⽅法中访问的是基本类型的封装类 (如 Intege ) 中预先定义好的 TYPE 字段。
第⼆步是调⽤诸如 getDeclaredMethods 的⽅法,以取得该类中定义的所有⽅法的列表。
⼀旦取得这个信息,就可以进⾏第三步了——使⽤ reflection API 来操作这些信息,如下⾯这段代码:
Class c = Class.forName("java.lang.String");
Method m[] = c.getDeclaredMethods();
System.out.println(m[0].toString());
它将以⽂本⽅式打印出 String 中定义的第⼀个⽅法的原型。
处理对象:
a.创建⼀个Class对象
b.通过getField 创建⼀个Field对象
c.调⽤Fiel
例如:
import flect.*;
import java.awt.*;
class SampleGet {
public static void main(String[] args) {
Rectangle r = new Rectangle(100, 325);
printHeight(r);
}
static void printHeight(Rectangle r) {
Field heightField;
Integer heightValue;
Class c = r.getClass();
try {
heightField = c.getField("height");
heightValue = (Integer) (r);
System.out.println("Height: " + String());
} catch (NoSuchFieldException e) {
System.out.println(e);
} catch (SecurityException e) {
System.out.println(e);
} catch (IllegalAccessException e) {
System.out.println(e);
}
}
}
安全性和反射:
在处理反射时安全性是⼀个较复杂的问题。反射经常由框架型代码使⽤,由于这⼀点,我们可能希望框架能够全⾯接⼊代码,⽆需考虑常规的接⼊限制。但是,在其它情况下,不受控制的接⼊会带来严重的安全性风险,例如当代码在不值得信任的代码共享的环境中运⾏时。
由于这些互相⽭盾的需求,Java编程语⾔定义⼀种多级别⽅法来处理反射的安全性。基本模式是对反射实施与应⽤于源代码接⼊相同的限制:
从任意位置到类公共组件的接⼊
类⾃⾝外部⽆任何到私有组件的接⼊
受保护和打包(缺省接⼊)组件的有限接⼊
不过⾄少有些时候,围绕这些限制还有⼀种简单的⽅法。我们可以在我们所写的类中,扩展⼀个普通的基本类
flect.AccessibleObject
类。这个类定义了⼀种setAccessible⽅法,使我们能够启动或关闭对这些类中其中⼀个类的实例的接⼊检测。唯⼀的问题在于如果使⽤了安全性管理
器,它将检测正在关闭接⼊检测的代码是否许可了这样做。如果未许可,安全性管理器抛出⼀个例外。
下⾯是⼀段程序,在TwoString 类的⼀个实例上使⽤反射来显⽰安全性正在运⾏:
public class ReflectSecurity {
public static void main(String[] args) {
try {
TwoString ts = new TwoString("a", "b");
Field field = DeclaredField("m_s1");
// field.setAccessible(true);
System.out.println("Retrieved value is " +
<(inst));
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
}
如果我们编译这⼀程序时,不使⽤任何特定参数直接从命令⾏运⾏,它将在field
.
get(inst)调⽤中抛出⼀个IllegalAccessException异常。如果我们不注释
field.setAccessible(true)代码⾏,那么重新编译并重新运⾏该代码,它将编译成功。最后,如果我们在命令⾏添加了JVM参数
-Djava.security.manager以实现安全性管理器,它仍然将不能通过编译,除⾮我们定义了ReflectSecurity类的许可权
限。
反射性能:(转录别⼈的啊)
反射是⼀种强⼤的⼯具,但也存在⼀些不⾜。⼀个主要的缺点是对性能有影响。使⽤反射基本上是⼀种解释操作,我们可以告诉JVM,我们希望做什么并且它满⾜我们的要求。这类操作总是慢于只直接执⾏相同的操作。
下⾯的程序是字段接⼊性能测试的⼀个例⼦,包括基本的测试⽅法。每种⽅法测试字段接⼊的⼀种形式 -- accessSame
与同⼀对象的成员字段协作,accessOther 使⽤可直接接⼊的另⼀对象的字段,accessReflection
使⽤可通过反射接⼊的另⼀对象的字段。在每种情况下,⽅法执⾏相同的计算 -- 循环中简单的加/乘顺序。
程序如下:
public int accessSame(int loops) {
m_value = 0;
for (int index = 0; index < loops; index++) {
m_value = (m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return m_value;
}
public int acces
sReference(int loops) {
TimingClass timing = new TimingClass();
for (int index = 0; index < loops; index++) {
timing.m_value = (timing.m_value + ADDITIVE_VALUE) *
MULTIPLIER_VALUE;
}
return timing.m_value;
}
public int accessReflection(int loops) throws Exception {
TimingClass timing = new TimingClass();
try {
Field field = TimingClass.class.
getDeclaredField("m_value");
access是什么意思啊了for (int index = 0; index < loops; index++) {
int value = (Int(timing) +
ADDITIVE_VALUE) * MULTIPLIER_VALUE;
field.setInt(timing, value);
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论