浅谈Java的反射机制

来源:互联网 发布:淘宝刷单怎么被发现 编辑:程序博客网 时间:2024/04/28 15:57

 概述

Java反射是可以让我们在运行时获得类的方法、属性、父类、接口等类的内部信息的机制。也就是说反射本身是一个“反着来”的过程。我们通过new创建类的实例时实际上是JVM在运行时根据这个类的class对象构建出来的,而反射是在运行时通过类的class对象获得他的内部定义信息。

Class类

我们知道使用javac能够将.java文件编译成.class文件,这个.class文件包含了我们对类的原始定义信息(构造函数、方法、属性、父类、接口等)。我们又知道.class文件在运行时会被类加载器(ClassLoader)加载到JVM中,当一个.class文件被加载后,JVM会为之生成一个class对象,我们在程序中通过new实例化的对象实际上是在运行时根据相应的class对象构造出来的。确切的说这个class对象是java.lang.Class<T>泛型类的一个实例比如Class<Human>对象即为一个封装了Human类的定义信息的Class<T>实例。由于java.lang.Class<T>类不存在公有构造函数,因此我们不能直接实例化这个类,我们可以通过一下方法获得一个class对象。例如我们定义了一个Human类

class Human {    private String sex;//性别    private Integer age;//年龄   public Human(String sex,Integer age){       this.sex=sex;       this.age=age;   }  public void eat(){//吃饭行为    System.out.println("吃早餐");    }}

1)通过类名获取其class对象

Class<Human> humanClass=Human.class;
2)通过类的完整路径名获取其class对象

try {  Class<Human> humanClass2=(Class<Human>) Class.forName("javaBasic.Human");} catch (ClassNotFoundException e) {  e.printStackTrace();  }
3)通过对象本身获取其class对象
Human h=new Human();Class<Human> humanClass3=(Class<Human>) h.getClass();
通过反射获取类中定义的内部信息

1) 获取类构造器

一旦我们获得了Human的class对象,我们就能够通过这个class对象获得Human类的原始定义信息,首先我们来获取Human类的构造器对象,有了构造器对象我们就能够构造出一个Human对象出来。注意,当通过反射获取到类的 Constructor、Method、Field对象后,在调用这些对象的方法之前,先将此对象的 accessible 标志设置为 true,以取消 Java 语言访问检查,可以提升反射速度。

Class<Human> humanClass=Human.class;try {Constructor<Human> c=humanClass.getConstructor(String.class,Integer.class);        c.setAccessible(true);       Human human=c.newInstance("男","21");human.eat();} catch (Exception e) {e.printStackTrace();} 

2) 获取类中定义的方法

要获取当前类中定义的方法可以用Class中的getDeclareMethods函数,他会获得当前类中定义的所有的方法(包括public、private、static等方法),它会返回一个Method对象数组,其中每一个Method的对象即表示类中定义的一个方法。要想获得类中定义的指定的方法可以用getDeclareMethod(Stirng name,Class...<T>parameterType)。

try {Class<Human> humanClass=Human.class;Human human=humanClass.newInstance();//初始化对象Method[] methods=humanClass.getDeclaredMethods();for(Method method:methods){System.out.println("方法名:"+method.getName());}//获得指定的方法Method eat=humanClass.getDeclaredMethod("eat", String.class);if(Modifier.isPrivate(eat.getModifiers())){//判断eat()的作用域是否为私有System.out.println("private");}eat.invoke(human);//调用eat()方法} catch (Exception e) {e.printStackTrace();} 
3)获取类中定义的属性

获取属性和获取方法类似,只不过将getMethod()换成了getField(),getDeclaredMethod()换成了getDeclareField()。

try {Class<Human> humanClass=Human.class;Field[] fields=humanClass.getDeclaredFields();for(Field field:fields){System.out.println("属性名:"+field.getName());}//获得指定的属性Field sex=humanClass.getDeclaredField("sex");} catch (Exception e) {e.printStackTrace();} 
4)获取父类和接口
我们先定义一个子类Man去继承Human类,如下,

class Man extends Human{private String beard;//有胡子@Override public void eat(){//吃饭行为    System.out.println("只吃午餐");    }}
然后通过class对象的getSuperClass()得到man的父类,通过getInterFaces获取接口。

Class<Man> manClass=Man.class;Class<?> humanClass= manClass.getSuperclass();Class<?>[] interfaces = manClass.getInterfaces();for (Class<?> i : interfaces) {   System.out.println(i.getName());}
总结
Java 反射是可以让我们在运行时获取类的函数、属性、父类、接口等 Class 内部信息的机制。通过反射还可以让我们在运行期实例化对象,调用方法,通过调用 get/set 方法获取变量的值,即使方法或属性是私有的的也可以通过反射的形式调用,这种“看透 class”的能力被称为内省,这种能力在框架开发中尤为重要。 有些情况下,我们要使用的类在运行时才会确定,这个时候我们不能在编译期就使用它,因此只能通过反射的形式来使用在运行时才存在的类(该类符合某种特定的规范,例如 JDBC),这是反射用得比较多的场景。
还有一个比较常见的场景就是编译时我们对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。比如 ORM 框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。这也是反射比较经典应用场景之一。



0 0
原创粉丝点击