(1) 反射的使用
当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类。在用它做某件事情之前必须加载那个类的Class对象。因此,那个类的.class文件对于JVM来说必须是可以获取到的:要么在本地上,要么可以通过网络获得。
Class类与java.lang.reflect类库一起对反射的概念进行了支持,该类库包含了Field、Method以及Constructor类。这些类的对象是由JVM在运行时创建的,用以表示未知类里面的而成员。
Class类的这三个常用的方法如下:
返回一个包含某些 | |
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 | |
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 注意这个时候就可以利用反射机制通过非默认构造器创建对象了。 如下代码所示。 |
但是反射也是可以获取和修改对象中成员变量或方法即使是非公共权限的,但是final域在遭受修改时是安全的。上面列出的只是其中获取公共权限方法、变量和构造器的三个调用方法。
(2) 反射与RTTI的区别
所以RTTI和反射之间真正的区别在于RTTI是编译器在编译时打开和检查.class文件,而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
(3) 反射的使用场景
反射的使用场景:①如果不记得一个类是否有某个方法,或者不知道一个类究竟可以做什么,而又不想通过索引或类的层次结构去查找JDK文档,这是用反射工具就能得到这个类有哪些方法。②在跨网络的远程平台上创建和运行对象。
(4) 反射的优缺点
优点:增加程序的灵活性;
缺点:不恰当地使用反射机制,会严重影响系统的性能。
(5) 反射提供的功能
① 得到一个对象所属的类;
② 获取一个类内所有公共权限的变量和方法;
③ 获取一个类内所有public构造器方法;
④ 运行时创建对象;
⑤ 运行时调用对象的方法。
如下代码展示了如何通过使用java.lang.reflect类库中Method和Constructor获取指定class对象中包含的方法和public访问权限的构造器方法。
java中使用反射的代码示例如下:
package exerise20160309;
import java.lang.reflect.*;
class T{
public int i;
}
public class Reflect extends T{
public int num;
public T[] sss;
private String str = "xidian";
public Reflect(int i){
System.out.println("通过反射机制构造带参数的实例对象成功");
}
private Reflect(int i,int j){
}
public void f(int i){
System.out.println("调用了f方法 i = "+i);
}
public String g(char c){
return "";
}
private int k(){
System.out.println("调用private权限的方法成功");
return 999;
}
public static void main(String[] args) throws ClassNotFoundException{
Class c = Class.forName("exerise20160309.Reflect");
Method[] methods = c.getMethods();
Constructor[] ctors = c.getConstructors();//返回的是public权限的构造器
System.out.println("1. 输出这个类中的所有public方法");
for(Method m : methods){
System.out.println(m.toString());
}
System.out.println("**********************************************************************");
System.out.println("2. 输出这个类中的所有public构造器方法:");
for(Constructor con : ctors){
System.out.println(con.toString());
}
System.out.println("**********************************************************************");
System.out.println("3. 根据反射机制调用非默认构造器创建实例对象");
Constructor constructor = ctors[0];
Reflect r = null;
try {
r = (Reflect) constructor.newInstance(3);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("**********************************************************************");
System.out.println("4. 应用反射机制调用方法");
try {
methods[1].invoke(r, 8866);
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
}
System.out.println("**********************************************************************");
System.out.println("5. 应用反射机制也可以调用类中的指定的方法个,即使是private访问权限的");
try {
Method mm = c.getDeclaredMethod("k");
System.out.println(mm);
mm.setAccessible(true);
mm.invoke(r);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("**********************************************************************");
System.out.println("6. 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段()也包含它继承自父类的可用的可访问的公共字段");
Field[] fs = c.getFields();
for(Field f:fs){
System.out.println(f);
}
System.out.println("**********************************************************************");
System.out.println("7. 访问对象中非public权限的成员变量");
try {
Field f = c.getDeclaredField("str");
f.setAccessible(true);
System.out.println(f.get(r));
} catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
e.printStackTrace();
}
}
}