-------android培训、java培训、期待与您交流! ----------
首先说一下对Class类的理解:Java类包含基本的属性、方法和构造函数等内容,为了对Java类进行集中管理,Java又将Java类的内容类别作为属性信息封装成一个新的类——Field类(属性)、Method(方法类)、Constructor(构造方法类),最后,将这些类打包成一个新的对象即Class类。通过对应的getXxx()方法获取对象。
然后,反射其实就是通过Field、Method、Constructor对象的相关方法操作或者调用原Java类的属性或方法的过程。反射和Java类的作用过程归纳如下:
总结起来反射就是由类的字节码文件对象映射到原Java类内容的方式,然后通过映射出的结果调用方法执行功能。
Java中类首先会被编译生产一个二进制的字节码文件即.class文件,那么在运行时,jvm会将该字节码文件由硬盘加载到内存中,然后将class放到运行时数据区的方法区内,之后,在堆内存中建立该类的字节码文件对象——java.lang.Class,这个对象就是Class类,它封装了该类的字节码文件对象的内容、数据结构等信息。Java中的反射技术其实就是通过字节码文件对象解析出该类的属性和方法等信息。
反射机制的步骤:
1、获取该类的字节码文件对象——Class类
2、实例化对象,由Class类获取类的属性、方法或构造函数等内容,不同内容对应不同的实例化对象。
3、通过实例化对象引用的相关方法,访问原类中的属性、调用特定方法或构造函数等完成特定操作。
获取类的Class对象的方式有三种:1、类名.class,弊端是必须要明确该类。2、对象.getClass(),必须要创建该类对象才能使用。3、Class.forName(指定类名),扩展性很强最为常用。eg:
//创建一个String类型的对象,利用它来获取Class对象
String string=new String("reflect");
//利用类名来获取
Class strCls1=String.class;
//利用对象来获取
Class strCls2=string.getClass();
//利用forName方法来获取
Class strCls3=Class.forName("java.lang.String");
注意,以上三种方式获取的对象是同一个对象,因他们对应于同一个字节码文件。
反射技术的具体用法:
1、Field类(属性对象),通过Class对象的getField或getFields方法获得类的属性对象,然后,可以利用该对象提供的基本方法去访问具体的属性值等信息。
两个返回Field对象的重要方法(Class的方法):getField(obj)——返回的是类的公共成员,getDeclaredField(obj)——返回的是类的已声明的成员(包括私有成员),在访问对象的公有和私有成员的方式也会有所不同,eg:
Person per=new Person("gao",27);
Class perCls=Class.forName("Person");
Field fieldName=perCls.getField("name");
//对于public的属性可以调用get(per)直接返回该值
String strPerson=fieldName.get(per).toString();
//对于private类型的age,则不能直接返回,需要暴力反射——三步走:1、获得Filed对象时要调用getDeclaredField方法。
//2、调用field对象的setAccessible方法取消限制访问符的限制。3、最后再调用get方法获得其值。
Field fieldAge=perCls.getDeclaredField("age");
fieldAge.setAccessible(true);
//可以调用set方法来设置值
fieldAge.set(per,23);
System.out.println(fieldAge.get(per));
2、Constructor对象,通过调用Class对象的getConstructor()、getConstructors()、getDeclaredConstructor()及getDeclaredConstructors()等方法来得到。另外,如果想要使用无参构造方法实例化该类的对象还可以直接使用Class对象的newInstance()方法。
//反射构造函数
Constructor<Person> con=perCls.getConstructor(String.class,int.class);//通过传入指定参数类型的Class来确定返回哪个参数列表的构造方法。
Object person=con.newInstance("zhang",34);//通过调用Constructor对象的newInstance方法直接创建对象。
3、Method对象,通过调用Class对象的geMethod()、getMethods()、getDeclaredMethod()及getDeclaredMethods()等方法来得到。方法里面的参数是需要调用方法的参数列表对应的Class列表,最后调用Method对象的invoke方法来执行功能。
Method method=perCls.getMethod("setName",String.class);//返回Method对象,映射到setName方法
method.invoke(per,"zhang");//调用invoke方法,注意参数是操作的对象及需要传递的具体参数值。
import java.lang.reflect.*;
class ReflectDemo
{
public static void main(String[] args) throws Exception
{
Person per=new Person("gao",27);
Class perCls=Class.forName("Person");
Field fieldName=perCls.getField("name");
//对于public的属性可以调用get(per)直接返回该值
String strPerson=fieldName.get(per).toString();
//对于private类型的age,则不能直接返回,需要暴力反射——三步走:1、获得Filed对象时要调用getDeclaredField方法。
//2、调用field对象的setAccessible方法取消限制访问符的限制。3、最后再调用get方法获得其值。
Field fieldAge=perCls.getDeclaredField("age");
fieldAge.setAccessible(true);
fieldAge.set(per,23);
System.out.println(fieldAge.get(per));
//反射构造函数
Constructor<Person> con=perCls.getConstructor(String.class,int.class);
Object person=con.newInstance("hehe",34);
Method method=perCls.getMethod("setName",String.class);
method.invoke(per,"zhang");
System.out.println(person.toString());
System.out.println(strPerson+fieldAge.get(per));
//System.out.println(perCls);
}
}
class Person
{
public String name;
private int age;
public Person(String name,int age)
{
this.name=name;
this.age=age;
}
public void setAge(int age)
{
this.age=age;
}
public void setName(String name)
{
this.name=name;
}
public String toString()
{
return "name:"+name+"--age:"+age;
}
}
总结:我对反射技术的理解是就是通过属性类对象或方法类对象映射到原类的对应属性和方法上,进而进行有针对性的调用过程。