JAVA反射机制

所谓的反射机制就是java语言在运行时拥有的一项自观的能力。通过这种能力可以彻底地了解自身的情况为下一步的动作做准备。下面介绍java的反射机制。

    Java的反射机制的实现要借助于4个类:ClassConstructorFieldMethod,其中Class代表的是类对象,Constructor代表类的构造器对象,Field代表类的属性对象,Method代表类的方法对象。通过这四个对象我们可以粗略看到一个类的各个组成部分。

    Class:

程序运行时,java运行时系统会对所有的对象进行运行时类型的处理。这项信息记录了每个对象所属的类,虚拟机通常使用运行时类型信息选择正确的方法来执行。我们可以借助Object类中定义的getClass()方法要得到指定对象的类对象,然后通过分析这个对象得到我们想要的信息,而Class本身又有很多重要的方法,此处重点将和Constructor,Field,Method类有关系的方法:

ü  Class.forName(“类名”) 表示载入指定的类,调用getDeclaredMethods

获取这个类中定义的方法列表

    实例:

package com.yilong.reflect;

import java.lang.reflect.Method;

public class Test1 {

    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) {

              e.printStackTrace();

       }

    }

}

    执行方法:

    编译:javac –d . Test1.java

    运行:java com.yilong.reflect.Test1 java.util.ArrayList

    Constructor:

    Constructor getConstructor(Class[] params) – 获得使用特殊的参数类型的公共构造函数;

    Constructor[] getConstructors() – 获得类的所有公共构造函数;

    Constructor getDeclaredConstructor(Class[] params) – 获得使用特定参数类型的构造函数(上面是公共)

    Constructor[] getDeclaredConstructors() – 获得类的所有构造函数(上面是公共”);

    Field:

    Field getField(String name) – 获得命名的公共字段;

    Field[] getFields() – 获得类的所有公共字段;

    Field getDeclaredField(String name) – 获得类声明的命名的字段;

    Fidld[] getDeclaredFields() – 获得类声明的所有字段。

    Method:

   Method getMethods(String name, Class[] params) – 使用特定的参数类型,获得命名的公共方法;

    Method[] getMethods() – 获得类的所有公共方法;

    Method getDeclaredMethod(String name, Class[] params) – 使用特定的参数类型,获得声明的命名的方法;

    Method[] getDeclaredMethods() – 获得类声明的所有的方法

    要向使用JAVAReflection,需要遵循三个步骤

第一步:获得你想要操作的类的java.lang.Class对象。在运行中的JAVA程序中,用

java.lang.Class类来描述类和接口等;

下面是获得Class对象的一些方法:

*  Class c = Class.forName(“java.lang.String”);

*  Class c = int.class;

*  Class c = Integer.TYPE;

第二步:调用诸如getDeclaredMethods的方法,取得该类中定义的所有方法的列表;

第三步:使用reflectionAPI来操作这些信息。

    下面是一些具体的实例:

   Java中使用Class.forName(“”).newInstance();对对象进行实例化,同时还需要掌握对其对象方法的调用方法。

    下面结合具体例子进行分析:

Ø  文件com.yilong.test.instance.NewClass.java

package com.yilong.test.instance;

public class NewClass {

  public boolean method() {

     System.out.println("ok!");

     return true;

  }

}

Ø  文件com.yilong.test.instance.Main.java

package com.yilong.test.instance;

import java.lang.reflect.Method;

public class Main {

  public static void main(String[] args) throws Exception {

     Object clazz = Class

.forName("com.yilong.test.instance.NewClass")

.newInstance();

     Method method = clazz.getClass().getMethod("method");

     Class returntype = method.getReturnType();

     method.invoke(clazz);

     System.out.println(method.getName() + "|"

+ returntype.getName());

  }

}

注意事项1:上面的getMethod()方法只适用于调用的方法没有参数的情况,如果方法要传递参数,还需要指定参数的类型(因为有重载),对应地,method.invoke()方法也是要传递具体的参数值的。

ü  public Method getMethod(String name,  Class<?>… parameterTypes)

           throws NoSuchMethodException,SecurityException

ü  public Object invoke(Object obj, Object... args)

throws IllegalAccessException,

IllegalArgumentException,  InvocationTargetException

ü  另外,还有一个重载的方法是可以拿到一个类里定义的所有的方法:

Class clazz = Class.forName("com.yilong.test.instancemethod.NewClass");

Method[] methods = clazz.getMethods();

//clazz只是拿到该类,还没实例化,如果实例化了,那么就要调用//newInstance.getClass().getMethods();

    下面是囊括了比较多的情况的例子

Ø  文件NewClass.java

package com.yilong.test.instance;

public class NewClass {

  public void method0() {

     System.out.print("0个参数的方法调用成功!");

  }

  public boolean method1(int id) {

     System.out.print("1个参数的方法调用成功!");

     return true;

  }

  public String method2(int id, String name) {

     System.out.print("2个参数的方法调用成功!");

     return "success";

  }

  public int method3(String[] strs) {

     System.out.print("参数为数组的方法调用成功!");

     return 1;

  }

}

Ø  文件Main.java

package com.yilong.test.instance;

import java.lang.reflect.Method;

public class Main {

  public static void main(String[] args) throws Exception {

     Object clazz = Class.forName

("com.yilong.test.instance.NewClass").newInstance();

     //调用0个参数的方法

     Method method0 = clazz.getClass().getMethod("method0");

     Class returntype0 = method0.getReturnType();

     method0.invoke(clazz);

     System.out.println("  --  " + method0.getName() + "|" +

returntype0.getName());

     //调用1个参数的方法

     Class[] parameterTypes1 = new Class[1];

     parameterTypes1[0] = int.class;

     Method method1 = clazz.getClass().getMethod("method1",

parameterTypes1);

     Class returntype1 = method1.getReturnType();

     method1.invoke(clazz, 1);

     System.out.println("  --  " + method1.getName() + "|" +

returntype1.getName());

     //调用2个参数的方法

     Class[] parameterTypes2 = new Class[2];

     parameterTypes2[0] = int.class;

     parameterTypes2[1] = String.class;

     Method method2 = clazz.getClass().getMethod("method2",

parameterTypes2);

     Class returntype2 = method2.getReturnType();

     method2.invoke(clazz, 2, "ok");

     //或者

     Object[] arguments = new Object[2];

     arguments[0] = 2;

     arguments[1] = "ok";

     method2.invoke(clazz, arguments);

     System.out.println("  --  " + method2.getName() + "|" +

returntype2.getName());

     //调用参数为数组的方法

     Class[] parameterType3 = new Class[1];

     parameterType3[0] = String[].class;

     Method method3 = clazz.getClass().getMethod("method3",

parameterType3);

     Class returntype3 = method3.getReturnType();

     Object[] arguments3 = new Object[1];

     String[] strs = new String[2];

     strs[0] = "aa";

     strs[1] = "bb";

     arguments[0] = strs;

     method3.invoke(clazz, arguments3);

     System.out.println("  --  " + method3.getName() + "|" +

returntype3.getName());

  }

}

注意事项2:通过Class.forName("com.yilong.test.instance.NewClass");方法得到的Class只能是放在classPath下面的class文件生成的,即对应项目中的bin目录下的文件,也就是说前面的目录已经默认是项目根路径 + bin”。而通过netURL方式new出来得到Class则不一定,具体实例如下:

System.out.println(System.getProperty("user.dir"));

//D:/MyEclipse/Proxy1

URL[] urls = new URL[] {new URL("file:/" +

System.getProperty("user.dir") + "/src")};

URLClassLoader ul = new URLClassLoader(urls);

Class c = ul.loadClass("com.yilong.designpattern.proxy.TimeProxy");

System.out.println(c);

项目中目录状态如下:

 

注意事项3:上述的newInstance()方法只能实例化没有参数的构造方法,要实例化有参数的构造方法,可以:

Constructor ctr = c.getConstructor(Moveable.class);//指定参数类型

Moveable m = (Moveable)ctr.newInstance(new Tank());//传递参数

Ø  文件Main.java

package com.yilong.test.instancemethod;

import java.lang.reflect.Constructor;

import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String[] args) {

       try {

           Class clazz = Class.forName

("com.yilong.test.instancemethod.NewClass");

           System.out.println(clazz);

           //调用1个参数的构造方法

           Constructor ctr1 = clazz.getConstructor(int.class);

           System.out.println(ctr1);

           ctr1.newInstance(1);

               //调用2个参数的构造方法

Constructor ctr2 = clazz.getConstructor(int.class,

String.class);

           System.out.println(ctr2);

           ctr2.newInstance(2, "ok");

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       } catch (IllegalAccessException e) {

           e.printStackTrace();

       } catch (InstantiationException e) {

           e.printStackTrace();

       } catch (SecurityException e) {

           e.printStackTrace();

       } catch (NoSuchMethodException e) {

           e.printStackTrace();

       } catch (IllegalArgumentException e) {

           e.printStackTrace();

       } catch (InvocationTargetException e) {

           e.printStackTrace();

       }

    }

}

Ø  文件NewClass.java

package com.yilong.test.instancemethod;

public class NewClass {

    public NewClass(int id) {

       System.out.println("1个参数的构造方法调用成功!");

    }

    public NewClass(int id, String str) {

       System.out.println("2个参数的构造方法调用成功!");

    }

    public void method(String[] strs, int i) {

       System.out.println("success!");

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值