基础知识:Java反射机制

反射机制的原理

   

一般来说,如果想生成一个类的对象,那么运行这个程序的JVM会去确认这个类的class对象是否已经加载。如果尚未加载,那么JVM会根据类名查找.class文件,并将其载入,一旦这个类的class对象被载入内存,它就可以被用来创建这个类的的所有对象

   

另外如果遇到一个未知类型的引用,(JVM?)通常会采用强制类型转换的形式来得到开发者想要的类型引用,如果执行了错误的类型转换,则会报一个ClassCastException异常

   

在以上两个过程中,Class类一直都在起作用,因为Class类实例包含的是一个类的全部信息,包括方法、属性、构造器等

   

如果不是在启动时去创建这个Class实例,而是在运行时获得这个Class类实例,那么我们就可以动态的去加载一个类,动态的调用类的方法,已经动态的去访问一个类的属性,反射机制就是为这种场景而产生的,反射机制的出发点就在于JVM会为每个类创建一个java.lang.Class类的实例,通过该对象可以获取该类的全部信息,然后通过java.lang.reflect包下的API以达到以上所述的动态需求

   

三种情况会导致一个Java类被加载到JVM

   

Student stu=new Student();

使用该类创建对象

   

System.out.println(student.count)

访问该类的静态成员

   

Class.forName("com.Student");

使用Class类的静态方法forName方法,动态的加载一个指定类名的类

ps…JDBC导入驱动类就是一个很常用的例子

   

三种得到一个类Class对象的方法

   

ClassforName方法返回的就是一个类的对象的引用

   

通过类的Class属性

Class<Student> clazz=Student.class;

   

通过getClass方法,这个方法是从Object类继承下来的

Student stu=new Student();

Class<Student> clazz=stu.getClass();

   

ps…获得类的Class对象后,就可以用这个对象创建和调用和访问这个类中的各种东西了

ps…Class类对象的方法getNamegetConstructorgetMethodnewInstance

   

Field的用法:操作类的成员变量

   

通过Class类的getDeclaredField方法可以获得一个Field类对象的引用,有了这个对象的引用之后,就可以调用该对象的getXXX方法,其中XXX包括intdoublebyte等获得某个成员变量

   

通过Field对象的使用来按照某一规则比较两个对象的大小

   

private static FieldReflect compareReflect(FieldReflect obj1,FieldReflect obj2)

   

三种获得的方式,本质上是三种获得Class对象的方式

   

//1

Field field=obj1.getClass().getDeclaredField("age");

//2

Field field=FieldReflect.class.getDeclaredField("age");

//3

Class clazz = Class.forName("com.FieldReflect.FieldReflect");

   

得到Class对象之后,就可以调用getDeclaredField方法得到Field对象的引用了

   

Field field = clazz.getDeclaredField("age");

   

得到Field对象的引用之后,就可以调用getXXX方法获得某一成员变量了

   

Field的用法:操作类的私有成员

   

首先我们写一个类,类的成员变量为私有

   

class PrivateFieldReflectClass {

private String name;

private int age;

public PrivateFieldReflectClass(String name, int age) {

super();

this.name = name;

this.age = age;

}

}

然后我们在主类中去通过反射机制得到类的Field

   

public class PrivateFieldReflectTest {

public static void main(String[] args) {

PrivateFieldReflectClass fieldReflect1 = new PrivateFieldReflectClass(

"Tong", 23);

// 访问私有变量

Class<PrivateFieldReflectClass> clazz = PrivateFieldReflectClass.class;

Field field = clazz.getDeclaredField("age");

// field.setAccessible(true);

System.out.println(field.getInt(fieldReflect1));

}

}

   

当我们试图去访问私有变量时,会发生错误java.lang.IllegalAccessException

如果我们想去访问私有变量,需要把Field的实例对象设置Accessible属性为true即可

   

Field的用法:覆盖toString方法,使其能够动态更改类对象的toString展示

   

需要覆盖类中的toString方法,主要思想就是用类对象的getDeclaredFields方法得到Field数组,循环遍历,得到相应的NameValue

   

class DataObject{

private String name;

private int age;

private String description;

private String other;

public DataObject(String name, int age, String description, String other) {

super();

this.name = name;

this.age = age;

this.description = description;

this.other = other;

}

@Override

public String toString() {

StringBuffer sb=new StringBuffer();

Field[] fields=DataObject.class.getDeclaredFields();

for (Field field : fields) {

sb.append(field.getName());

sb.append("=");

sb.append(field.get(this));

sb.append("\n");

}

return sb.toString();

}

}

   

Method的用法:操作类的方法

   

Method类,代表的是类的方法,包括静态和非静态的,与Field类似,通过反射机制,具体来说就是通过Class类对象的getMethod方法可以获得Method类的对象,然后通过该对象额invoke方法,将类名作为参数传入该方法,即可完成方法的调用

   

首先类中定义两个方法

   

public class MethodReflect {

public void m1() {

System.out.println("method 1");

}

public void m2() {

System.out.println("method 2");

}

}

   

然后在main函数就可以利用反射机制获取并调用想要的方法了

反射机制的过程仍旧是先得到类的对象的引用,然后通过类对象的getDeclaredMethod方法得到方法类对象的引用,然后创建一个类的对象,然后利用方法对象的invoke方法将刚创建的类对象作为参数传入,注意,这里如果方法有参数,需要将参数列表也作为参数传入invoke

   

Class clazz=MethodReflect.class;

Method method=clazz.getDeclaredMethod("m1");

MethodReflect methodReflect=new MethodReflect();

method.invoke(methodReflect);

   

Constructor类的用法:利用反射机制实例化一个类

   

一般来说,我们可以通过new关键字实例化一个类,也就是创建一个类的对象,而如何通过反射机制实例话一个类呢,其实不管是通过new关键字还是通过反射,都是去调用类的构造函数,如果是去调用无参的构造函数,我们可以使用ClassnewInstance方法。如果是要用到有参的构造函数的话,我们就需要用到反射包下的Constructor

   

首先也是要得到类的对象的引用

   

Class<Student> clazz1=Student.class;

//无参:通过newInstance

Student student1=clazz1.newInstance();

//有参:通过构造器

Constructor<Student> constructor=clazz1.getConstructor(String.class,int.class);

student1=constructor.newInstance("Tong",23);

   

posted @ 2015-05-11 17:07  keedor  阅读(158)  评论(0编辑  收藏  举报