浅析Java反射机制
如果你感觉到图片里有东西在转动,那么在看完这篇博客之后休息吧,你已经累了。
反射,很容易让人与RTTI混淆起来。虽然二者都是获取类型信息的机制,但是二者是存在本质区别的。RTTI(Run-Time Type Information,运行时类型信息)是在编译时获取.class文件,而反射机制在编译阶段是获取不到.class文件的,只有在运行时才能去得到.class文件(当然也有可能找不到)。
接下来,将全面介绍一下反射机制。
什么是反射?
反射,是个简单且神奇的东西。说它简单,是因为它真的不难,虽然很多人一直觉得反射的概念很抽象,而且在普通的编程中很少用到,但是只要鼓起勇气往前走几步,就会看到,原来反射就是用来检查未知类中的基本信息,并予以返回。Eckel曰过:当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类。看吧,仅仅是检查一下而已,简单吧。说它神奇,是因为反射可以让我们获取进行中的类的基本信息,这在C和C++里是不可想象的,而且反射也可以实现RMI(Remote Method Invoke,远程方法调用),我们可以呆在北京调用纽约的类创建和运用对象,想想就觉得神奇额,世界因为我们而变小,不愧是技术宅拯救全世界。我给反射下的定义是:反射,就是获取运行中的程序中一个未知类的基本的信息并对这些基本信息进行操作的机制。
反射怎么用?
那么,既然反射这么有用,要怎么用呢?
RTTI中得到类型信息有两种方法:Class.forName()和使用类字面常量。在反射机制里,考虑到我们在编译时不知道该类是否存在,因此类字面常量的使用在反射里就无从说起了,我们在反射里使用的是Class.forName()方法(而在RTTI中,使用类字面常量效果更好),你会不会在想:如果找不到这个类,会不会在编译时抛出ClassNotFoundException呢?答案是No。因为forName方法在编译时的结果是不可知的。具体的使用,我们将通过以下几个示例介绍:
// 父类class Father{String fName;public int a;public Father(){}public Father(String fName){this.fName = fName;} // end constructorvoid fFun1(){System.out.println("Father.fFun1()");}void fFun2(String str){System.out.println("Father.fFun2()" + str);}public int fFun3(){System.out.println("Father.fFun3()");return 0;}} // end class Father// 子类class Son extends Father{String sStr;public Son(String sStr){this.sStr = sStr;}public void sFun1(){System.out.println("Son.sFun1()");}public void sFun2(int i){System.out.println("Son.sFun2()");}void sFun3(){System.out.println("Son.sFun3()");}} // end class Son
Class c = Class.forName("com.tuyage.typeInfo.Son");
Constructor[] cons1 = c.getConstructors();Constructor[] cons2 = c.getDeclaredConstructors();System.out.println("#c.getConstructors()");for(Constructor con: cons1){System.out.println(con.toString());} // end forSystem.out.println("#c.getDeclaredConstructors()");for(Constructor con : cons2){System.out.println(con.toString());} // end for
Method[] meth1 = c.getMethods();Method[] meth2 = c.getDeclaredMethods();System.out.println("#c.getMethods()");for(Method m: meth1){System.out.println(m.toString());} // end forSystem.out.println("#c.getDeclaredMethods()");for(Method m : meth2){System.out.println(m.toString());} // end for
Field[] field1 = c.getFields();Field[] field2 = c.getDeclaredFields();System.out.println("#c.getFields()");for(Field f: field1){System.out.println(f.toString());} // end forSystem.out.println("#c.getDeclaredFields()");for(Field f : field2){System.out.println(f.toString());} // end for