java反射(2)

来源:互联网 发布:慢走丝统盈编程 编辑:程序博客网 时间:2024/06/07 06:09
所谓的反射机制就是java语言在运行时拥有一项自观的能力。

通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。

Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。

在JDK在主要实现反射机制类都位于java.lang.reflect包中:

1.Class类:代表一个类

2.Field类:代表类的成员变量(成员变量也称为类的属性)

3.Method类:代表类的方法。

4.Constructor类:代表类的构造方法。

5.Array类

后面四个看看API就明白了



这里主要说下Class类

Class是Reflection故事起源。针对任何您想探勘的class,唯有先为它产生一个Class object。

Class对象怎样产生的?

根据API解释

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object。注意Class并没有public constructor。


怎么得到Class对象?

在我上一篇博客上反射(1)也有提到。

这里再说一下:

一般有三种方式得到Class对象

1、利用每个类都有的getClass()方法(java.lang.Object),

如String str = "xx";

Class c1 = str.getClass();

c1.getName();得到java.lang.String

2、利用static method------Class.forName()(最常被使用)

如Class c2 = Class.forName ("java.lang.String");

c2.getName();得到java.lang.String


3、类名.class方法

Class c3 = String.class;

c3.getName();得到java.lang.String


1)对于一些基本类型数据还可以通过.TYPE的方式,且看下面代码


package com.testclass;import java.lang.reflect.Method;public class Reflection {public static void main(String args[]){try {/** * 我们的程序中的每个类都有一个相应的Class对象.每当新的类被编译 * 完成,就会产生一个Class对象存储与相同的.class文件内.执行期间 * 当你想要产生该class的对象是,JVM便会检查该型别的Class对象是   * 否被加载.如果没被加载,JVM会根据名称找到.class文件并加载它 *  * java中每个class都有一个相应的Class对象,当编写好一个类,编译完成后, * 在生成的.class文件中,就产生一个Class对象,用来表示 * 这个类的类型信息。获得Class实例的三种方式 *///1、使用Class的静态方法forName(),用类的名字获取一个Class实例Class c = Class.forName("com.testclass.TestOne");System.out.println(c.getName());//输出com.md5.TestOneTestOne test = (TestOne)c.newInstance();//产生这个class类对象的一个实例,调用该类的无参的构造方法,作用等同于new TestOne();/** * 有异常处理 * newInstance创建对象实例的时候会调用无参的构造函数, * 所以必需确保类中有无参数的构造函数,否则将会抛出java.lang.InstantiationException异常。 */System.out.println("=====================================================");//2、利用对象调用getClass()方法获取该对象的的Class实例,对象实现存在TestOne  test2 = new TestOne();Class c2 = test2.getClass();System.out.println(c2.getName());//输出com.md5.TestOneMethod[] m = c2.getDeclaredMethods();//得到TestOne中的所有类型的自定义的方法,//Method[] m = c2.getMethods();//得到TestOne中的public类型的方法,不仅仅是自定义的,还有继承于Object类的System.out.println("TestOne中的所有方法");for(Method m2 : m){System.out.println(m2);}System.out.println("======================================================");//3-1、运用.class方式获取Class实例(类)Class c3 = TestOne.class;System.out.println(c3.getName());//输出com.md5.TestOne//3-2 运用.class的方式获取Class实例(基本类型)Class c4 = int.class;System.out.println("基本类型Class实例:"+c4.getName());//输出int//3-3运用.class的方式获取Class实例(封装类型类型)Class c5 = Integer.TYPE;//获取的是这个Integer类型System.out.println(c5.getName());//输出intClass c6 = Integer.class;//获取的是这个Integer的Class对象System.out.println(c6.getName());//输出java.lang.Integer} catch (ClassNotFoundException e) {//如果包下不存在相应的com.md5.TestOne的.class文件,会抛出异常// TODO Auto-generated catch blocke.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}//使用一般方法构造实例TestOne two = new TestOne();//静态块只会被加载一次,第二次创建对象,不会再加载静态块,只执行构造方法}}class TestOne{static {System.out.println("静态块执行");}public TestOne(){System.out.println("构造方法执行");}void getTest(){}public void getTest2(){}}

2)对于method方法还可以输出方法的参数等信息、

package com.testclass;import java.lang.reflect.Method;public class Reflection2 {public static void main(String[] args) {// TODO Auto-generated method stubtry {Class c = Class.forName("com.testclass.Test2");Method[] m = c.getDeclaredMethods();for(Method method : m){Class[] pre = method.getParameterTypes();/** * 按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。 * 如果底层方法不带参数,则返回长度为 0 的数组 */for(Class cc : pre){//System.out.println(cc);//输出所有参数类型System.out.println(cc.getName());//输出所有参数类型,这样输出更好}}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}//Class c = Integer.class;//System.out.println(c);//输出class java.lang.Integer//Class c = int.class;//System.out.println(c);//输出int}}class Test2{public void getTest(Integer a,int b){}}


3)利用反射可以验证一个对象是否属于这个类

package com.testclass;public class Reflection3 {public static void main(String[] args) {try {Class c = Class.forName("com.testclass.Test2");//!!!String s = "";System.out.println(c.isInstance(s));//输出falseSystem.out.println(c.isInstance(new Test2()));//输出true} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

4)反射在框架中用的很多,工厂模式,当你不断的new 就不断的分配内存空间,当你new到一定程度没有空间的时候,不就出问题了。一般都不考虑用new来构造实例,除非特殊情况。

new是不在内存中有了空间的分配,当知道类型的时候可以new,当不知道类型的时候,不能new


还要明白在java里面任何class都要装载在虚拟机上才能运行。Class.forName就是装载类用的(和new 不一样,要分清楚)。

Class.forName("oracle.jdbc.driver.OracleDriver");只有加载了数据库驱动(就是加载这个.class文件)之后,才能用DriverManager。

DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl","xxx","xxx");


5)利用反射,动态加载类

要动态加载类,必须有个接口或者是抽象类(A),反射所加载的类是A的实现类或者是子类,否则动态加载的类毫无意义可言。

AA a = (AA)(Class.forName("xxx.xxx.xxx.AAImplClass").newInstance());//其中的forName中的类路径可以动态的传进来


7)数组对象的反射(这个还在研究中)

int[] a = new int[2];
int[]b = new int[5];
System.out.println(a.getClass().getName());//输出结果 [I
System.out.println(b.getClass().getName());////输出结果 [I



6)此外,我们还可以在servlet中发现发射的影子

有时我们会奇怪,当我们把一个form表单提交给一个servlet处理时,我们并没有创建这个servlet对象,但是怎么呢调用其中的方法的呢?

当一个request请求传递给web服务器后,web服务器利用发射机制创建相应servlet对象,这个对象调用init方法将这个对象实例加载内存中(init方法只调用一次),然后就可以用这个实例调用servlet中的各种方法





原创粉丝点击