您的位置:首页 > 编程语言 > Java开发

Java反射基本知识

2014-07-09 14:35 148 查看
       Java 语言允许通过程序化的方式间接对Class 进行操作,Class 文件由类装载器装载后,在JVM 中将形成一份描述Class 结构的元信息对象,通过该元信息对象可以获知Class 的结构信息:如构造函数、属性和方法等。Java 允许用户借由这个Class 相关的元信息对象间接调用Class 对象的功能,这就为使用程序化方式操作Class 对象开辟了途径。

public class Car
{
private String brand;
private String color;
private int maxSpeed;

public Car(){}
}


一般情况下,我们会使用如下的代码创建Car 的实例:

Car car = new Car();

car.setBrand("红旗CA72");

或者:

Car car = new Car("红旗CA72","黑色");

package com.baobaotao. reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectTest {
public static Car initByDefaultConst() throws Throwable
{
//①通过类装载器获取Car类对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass("com.baobaotao.reflect.Car");
//②获取类的默认构造器对象并通过它实例化Car
Constructor cons = clazz.getDeclaredConstructor((Class[])null);
Car car = (Car)cons.newInstance();
//③通过反射方法设置属性
Method setBrand = clazz.getMethod("setBrand",String.class);
setBrand.invoke(car,"红旗CA72");

Method setColor = clazz.getMethod("setColor",String.class);
setColor.invoke(car,"黑色");
Method setMaxSpeed = clazz.getMethod("setMaxSpeed",int.class);
setMaxSpeed.invoke(car,200);
return car;
}
public static void main(String[] args) throws Throwable {
Car car = initByDefaultConst();
car.introduce();
}
}


 

在1处,我们获取当前线程的ClassLoader,然后通过指定的全限定类“com.baobaotao.beans.Car”装载Car 类对应的反射实例

在2处,  我们通过获取构造函数对象,然后调用newInstance()方法来实例化对象

在3处,我们过Car 的反射类对象的getMethod(String methodName,Class paramClass)获取属性的Setter 方法对象

 

     类装载器(ClassLoader)是寻找类的节码文件并构造出在JVM内部表示的组件。类装载器装载类的步骤

    1 装载:寻找和装载class文件

     2 链接

              a.校验:检查载入class文件的正确性

              b.准备:为静态变量分配存储空间

              3.解析,将符号引用解释为直接引用

     3初始化:对静态变量和静态代码执行初始化工作

    类装载工作是由ClassLoader及其子类来完成,ClassLoader是一个重要的Java运行时系统的重要组件,它负责完成class文件的寻找和加载。JVM在运行的时候需要三个classloader: ClassLoader(根加载器)ExtClassLoader(扩展加载器) AppClassLoader(系统加载器)根装载器不是ClassLoader 的子类,它使用C++编写,因此我们在Java 中看不到它,根装载器负责装载JRE 的核心类库,如JRE 目标下的rt.jar、charsets.jar
等。ExtClassLoader 和AppClassLoader 都是ClassLoader 的子类。其中ExtClassLoader 负责装载JRE 扩展目录ext 中的JAR 类包;AppClassLoader 负责装载Classpath 路径下的类包。JVM 装载类时使用“全盘负责委托机制”,“全盘负责”是指当一个ClassLoader 装载一个类的时,除非显式地使用另一个ClassLoader,该类所依赖及引用的类也由这个ClassLoader 载入;“委托机制”是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全角度考虑的,试想如果有人编写了一个恶意的基础类(如java.lang.String)并装载到JVM
中将会引起多么可怕的后果。但

是由于有了“全盘负责委托机制”,java.lang.String 永远是由根装载器来装载的,这样就避免了上述事件。

 

 ClassLoader 重要方法

Class loadClass(String name)

name 参数指定类装载器需要装载类的名字,必须使用全限定类名,如com.baobaotao.

beans.Car。该方法有一个重载方法loadClass(String name ,boolean resolve),resolve 参数告

诉类装载器是否需要解析该类。在初始化类之前,应考虑进行类解析的工作,但并不是所

有的类都需要解析,如果JVM 只需要知道该类是否存在或找出该类的超类,那么就不需

要进行解析。

Class defineClass(String name, byte[] b, int off, int len)

将类文件的字节数组转换成JVM 内部的java.lang.Class 对象。字节数组可以从本地文

件系统、远程网络获取。name 为字节数组对应的全限定类名

从本地文件系统载入Class 文件,如果本地文件系统不存在该Class 文件,将抛出

ClassNotFoundException 异常。该方法是JVM 默认使用的装载机

从本地文件系统载入Class 文件,如果本地文件系统不存在该Class 文件,将抛出

ClassNotFoundException 异常。该方法是JVM 默认使用的装载机

ClassLoader getParent()

获取类装载器的父装载器,除根装载器外,所有的类装载器都有且仅有一个父装载器,

ExtClassLoader 的父装载器是根装载器,因为根装载器非Java 编写,所以无法获得,将返

回null。

     类文件被装载并解析后,在JVM 内将拥有一个对应的java.lang.Class 类描述

对象,该类的实例都拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联

ClassLoader 的引用

每一个类在JVM 中都拥有一个对应的java.lang.Class 对象,它提供了类结构信息的描

述。数组、枚举、注解以及基本Java 类型(如int、double 等),甚至void 都拥有对应的

Class 对象。Class 没有public 的构造方法。Class 对象是在装载类时由JVM 通过调用类装

载器中的defineClass()方法自动构造的

Class 反射对象描述类语义结构,可以从Class 对象中获取构造函数、成员变量、方法

类等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些

反射对象类在java.reflect 包中定义,下面是最主要的三个反射类

Constructor:类的构造函数反射类,通过Class#getConstructors()方法可以获得类的

所有构造函数反射对象数组。在JDK5.0 中,还可以通过getConstructor(Class...

parameterTypes)获取拥有特定入参的构造函数反射对象。Constructor 的一个主要方

法是newInstance(Object[] initargs),通过该方法可以创建一个对象类的实例,相当

于new 关键字。在JDK5.0 中该方法演化为更为灵活的形式:newInstance (Object...

initargs)。

Method:类方法的反射类,通过Class#getDeclaredMethods()方法可以获取类的所有

方法反射类对象数组Method[]。在JDK5.0 中可以通过getDeclaredMethod(String

name, Class... parameterTypes)获取特定签名的方法,name 为方法名;Class...为方法

入参类型列表。Method 最主要的方法是invoke(Object obj, Object[] args),obj 表示

操作的目标对象;args 为方法入参,代码清单3-10③处演示了这个反射类的使用方

法。在JDK 5.0 中,该方法的形式调整为invoke(Object obj, Object... args)。此外,

Method 还有很多用于获取类方法更多信息的方法:

Method 还有很多用于获取类方法更多信息的方法:

1)Class getReturnType():获取方法的返回值类型;

2)Class[] getParameterTypes():获取方法的入参类型数组;

3)Class[] getExceptionTypes():获取方法的异常类型数组;

4)Annotation[][] getParameterAnnotations():获取方法的注解信息,JDK 5.0 中的新方法;

Field:类的成员变量的反射类,通过Class#getDeclaredFields()方法可以获取类的成

员变量反射对象数组,通过Class#getDeclaredField(Str
ad08
ing name)则可获取某个特定

名称的成员变量反射对象。Field 类最主要的方法是set(Object obj, Object value),obj

表示操作的目标对象,通过value 为目标对象的成员变量设置值。如果成员变量为

基础类型, 用户可以使用Field 类中提供的带类型名的值设置方法, 如

setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 编程