Java 反射的详解

来源:互联网 发布:少女时代减肥 知乎 编辑:程序博客网 时间:2024/09/21 08:54

今天我要学习一下反射:

  一,先看一下反射的概念

根据网文,java中的反射机制可以如此定义:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

 二,反射机制的作用

              1,反编译:.class-->.java

              2,通过反射机制访问java对象的属性,方法,构造方法等;

             这样好像更容易理解一些,下边我们具体看怎么实现这些功能。

 三,反射机制如何实现    

首先不得不提到的是java.lang.Class这个类。

有这么一段话:

Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。

也就是说,ClassLoader找到了需要调用的类时(java为了调控内存的调用消耗,类的加载都在需要时再进行,很抠但是很有效),就会加载它,然后根据.class文件内记载的类信息来产生一个与该类相联系的独一无二的Class对象。该Class对象记载了该类的字段,方法等等信息。以后jvm要产生该类的实例,就是根据内存中存在的该Class类所记载的信息(Class对象应该和我所了解的其他类一样会在堆内存内产生、消亡)来进行。

而java中的Class类对象是可以人工自然性的(也就是说开放的)得到的(虽然你无法像其他类一样运用构造器来得到它的实例,因为

Class对象都是jvm产生的。不过话说回来,客户产生的话也是无意义的),而且,更伟大的是,基于这个基础,java实现了反射机制。

四,具体功能实现 

1.获取class对象的三种方式:

Java中有一个Class用于代表某一个类的字节码。

Java提供了三种方式获取类的字节码:

forName()  forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装

类名.class

对象.getClass()

示例代码如下:

/** * 加载类的字节码的3种方式 * @throws Exception * */public void test1() throws Exception {// 方式一Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");// 方式二Class clazz2 = Person.class;// 方式三Person p1 = new Person();Class clazz3 = p1.getClass();}
2.通过Class类获取类型的一些信息

1.getName()类的名称(全名,全限定名)2 getSimpleName()类的的简单名称(不带包名)3. getModifiers(); 类的的修饰符4.创建对象  无参数构造创建对象  newInstance()5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例Constructor<T> getConstructor(Class<?>... parameterTypes)
示例代码如下:

/** * 通过Class对象获取类的一些信息 *  * @throws Exception * */private static void test2() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");// 获取类的名称String name = clazz1.getName();System.out.println(name); // cn.itcast.gz.reflect.Person// 获取类的简单名称System.out.println(clazz1.getSimpleName()); // Person// 获取类的修饰符int modifiers = clazz1.getModifiers();System.out.println(modifiers);// 构建对象(默认调用无参数构造.)Object ins = clazz1.newInstance();Person p = (Person) ins;System.out.println(p); // cn.itcast.gz.reflect.Person@c17164// 获取指定参数的构造函数Constructor<?> con = clazz1.getConstructor(String.class, int.class);// 使用Constructor创建对象.Object p1 = con.newInstance("jack", 28);System.out.println(((Person) p1).getName());}
3.通过Class类获取类型中的方法的信息

1.获取公共方法包括继承的父类的方法getMethods()返回一个数组,元素类型是Method2.获取指定参数的公共方法getMethod("setName", String.class);3.获得所有的方法,包括私有Method[] getDeclaredMethods()  4.获得指定参数的方法,包括私有Method getDeclaredMethod(String name, Class<?>... parameterTypes)
示例代码如下:

/** * 获取公有方法. * @throws Exception * */private static void test3() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");// 1.获取非私用方法(包括父类继承的方法)Method[] methods = clazz1.getMethods();System.out.println(methods.length);for (Method m : methods) {// System.out.println(m.getName());if ("eat".equals(m.getName())) {m.invoke(clazz1.newInstance(), null);}}}

/** * 获取指定方法签名的方法 *  * @throws Exception * */private static void test4() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");// 获取指定名称的函数Method method1 = clazz1.getMethod("eat", null);method1.invoke(new Person(), null);}

/** * 获取指定方法名且有参数的方法 *  * @throws Exception * */private static void test5() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");Method method = clazz1.getMethod("eat", String.class);method.invoke(new Person(), "包子");}/** * 获取指定方法名,参数列表为空的方法. *  * @throws Exception * */private static void test4() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");// 获取指定名称的函数Method method1 = clazz1.getMethod("eat", null);method1.invoke(new Person(), null);}


/** * 反射静态方法 * @throws Exception * */private static void test7() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");Method method = clazz1.getMethod("play", null);method.invoke(null, null);}/** * 访问私有方法 暴力反射 * @throws Exception * */private static void test6() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");Method method = clazz1.getDeclaredMethod("movie", String.class);method.setAccessible(true);method.invoke(new Person(), "苍老师");}

4.通过Class类获取类型中的字段的信息

1.获取公共字段Field[] getFields()  2.获取指定参数的公共字段Field getField(String name)  3.获取所有的字段Field[] getDeclaredFields()  4.获取指定参数的字段,包括私用Field getDeclaredField(String name)  

示例代码如下:

/** * 获取公有的字段 * */private static void test8() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");Field[] fields = clazz1.getFields();Person p = new Person();System.out.println(fields.length);for (Field f : fields) {System.out.println(f.getName());if ("name".equals(f.getName())) {System.out.println(f.getType().getName());f.set(p, "jack");}}System.out.println(p.getName());}

/** * 获取私有的字段 * @throws Exception * */private static void test9() throws Exception {Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");Field field = clazz1.getDeclaredField("age");System.out.println(field.getName());field.setAccessible(true);Person p = new Person();field.set(p, 100);System.out.println(p.getAge());}


好了,反射的知识其实也不是很难~


0 0
原创粉丝点击