微信搜索《Java鱼仔》,每天一个知识点不错过
(一)什么是反射?
反射就是将类的各个组成部分封装为其他对象。
在详细了解反射机制之前,我们先来了解一下java代码在计算机中的运行过程:
比如当我们编写好一个类:Student.java,里面包含学生的姓名和年龄,构造方法,其他方法。
第一个阶段:Source阶段
javac会把我们写的代码编译成.class字节码文件,保存在硬盘中,这个文件中保存着该类的类名,成员名,构造方法等等。
第二个阶段:Class阶段
Class阶段会把字节码文件中的信息转化成class类对象,比如成员变量用Field[]保存,构造方法用Constructor[]保存,成员方法用Method[]保存
第三个阶段:Runtime阶段
通过new Student(),根据第二个阶段的类对象创建出Student对象 这里的第二个阶段,将类的各个组成部分封装为其他对象就是反射机制。
反射的好处:
1.可以在程序运行过程中操作对象。
2.解耦,提高程序可扩展性。
(二)获取字节码Class对象的三种方式
获取Class对象有三种方式,分别对应于前面的三个阶段:
1.对应于第一个阶段的方法是将字节码文件加载进内存中:
class.forname("全类名");
2.第二个阶段已经生成了class类对象,因此方法如下:
类名.class;
3.第三个阶段生成了对象,方法如下:
对象.getclass();
注意:
同一个字节码文件(.class)在一次程序运行过程中只会被加载一次,通过以上三种方法创建的class对象是同一个。
通过代码演示: 新建Student类:
publicclassStudent { privateStringname; privateintage; //方便后期测试的成员变量publicinta; publicStudent(){} publicStudent(Stringname, intage,inta) { this.name=name; this.age=age; this.a=a; } publicStringgetName() { returnname; } publicvoidsetName(Stringname) { this.name=name; } publicintgetAge() { returnage; } publicvoidsetAge(intage) { this.age=age; } publicStringtoString() { return"Student{"+"name='"+name+'\''+", age="+age+", a="+a+'}'; } }
测试获取Class对象的三种方式
packagecom.sdxb.reflect; publicclassreflectTest { publicstaticvoidmain(String[] args) throwsClassNotFoundException { //方法一Classcls1=Class.forName("com.sdxb.reflect.Student"); System.out.println(cls1); //方法二Classcls2=Student.class; System.out.println(cls2); //方法三Studentstudent=newStudent(); Classcls3=student.getClass(); System.out.println(cls3); //判断是否是同一对象System.out.println(cls1==cls2); System.out.println(cls1==cls3); } }
(三)Class获取对象方法
1.1 获取成员变量
FieldgetField(Stringname) //获取指定名称public修饰的成员变量Field[] getFields() //获取所有public修饰的成员变量FieldgetDeclaredField(Stringname) //获取指定名称成员变量Field[] getDeclaredFields() //获取所有成员变量
1.2 操作成员变量
Objectget(Objectobj) //通过Field获取对象voidset(Objectobj, Objectvalue) //修改Field的值
通过代码演示
publicclassFieldTest { publicstaticvoidmain(String[] args) throwsClassNotFoundException, NoSuchFieldException, IllegalAccessException { Classcls=Class.forName("com.sdxb.reflect.Student"); //1.获取所有public的成员变量Field[] fields=cls.getFields(); for (Fieldfield:fields) { System.out.println(field); } //2.获取指定名字的public成员变量Fielda=cls.getField("a"); Studentstudent=newStudent(); //3.操作Field的方法,get和setSystem.out.println(a.get(student)); a.set(student,10); System.out.println(student); //4.获取所有成员变量Field[] declaredFields=cls.getDeclaredFields(); for (Fieldf : declaredFields) { System.out.println(f); } } }
这里的两个操作Field的方法只能操作public修饰的变量,如果需要访问其他修饰符修饰的元素,则要添加安全许可:
a.setAccessible(true);
2.1 获取构造方法
Constructor<T>getConstructor(Class<?>... parameterTypes) //根据参数不同获取指定的public构造方法Constructor<?>[] getConstructors() //获取所有public构造方法Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes) //根据参数不同获取指定的构造方法Constructor<?>[] getDeclaredConstructors() //获取所有构造方法
2.2 操作构造方法
T newInstance(Object... initargs) //创建对象
通过代码演示其中一两种操作:
public class reflectTest2 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class cls = Class.forName("com.sdxb.reflect.Student"); //有参构造方法 Constructor constructor = cls.getConstructor(String.class, int.class, int.class); Object student = constructor.newInstance("sdxb", 24, 1); System.out.println(student); //无参构造方法 Constructor constructor2 = cls.getConstructor(); Object student2 = constructor2.newInstance(); System.out.println(student2); //无参构造方法可以用下面的方式代替 cls.newInstance(); } }
3.1 获取成员方法
Method getMethod(String name, Class<?>... parameterTypes) //根据名称和参数类型获取public方法 Method[] getMethods() //获取所有public方法 Method getDeclaredMethod(String name, Class<?>... parameterTypes) //根据名称和参数类型获取方法 Method[] getDeclaredMethods() //获取所有方法
3.2 成员方法的操作
Object invoke(Object obj, Object... args) //执行成员方法
为了方便测试,我为Student类增加了两个成员方法:
public void run(){ System.out.println("run"); } public void run(int speed){ System.out.println("run"+speed); }
接着对成员方法的反射进行测试:
publicclassreflectTest3 { publicstaticvoidmain(String[] args) throwsNoSuchMethodException, InvocationTargetException, IllegalAccessException { Classcls=Student.class; Studentstudent=newStudent(); //无参方法Methodrun=cls.getMethod("run"); run.invoke(student); //带参数方法Methodrun2=cls.getMethod("run", int.class); run.invoke(student,1); } }
(四)总结
java的反射机制在框架中应用十分广泛,被誉为是框架的灵魂。原因是框架是一个半成品,我们无法通过new去创建框架中定义的类,因此反射起到了很大的作用。