笔记:Java——反射机制

Java 2018-01-26

反射虽然在我们工作中用到的地方不是很多, 但是我们所有的框架基本都会用到反射技术去实现相应的功能, 学好反射技术有利于我们以后阅读框架源码, 更好的理解别人的一个思想和逻辑。 从而使我们更加得心应手的去做开发的工作。

任何一个类都是Class的实例对象,这个实例对象有三种表示方法

Class类

Java中,一切皆对象,可以认为类也是对象,类是java.lang.Class类的实例对象(任何一个类都是Class的实例对象,这个实例对象有三种表示方法)。如Student,Person都是Class类的对象。

一.什么是反射:

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。 大家能发现这里边比较核心的一句话就是, 对于任意一个类, 都能获取到这个类的所有属性和方法, 没错, 你没有看错, 是所有的属性和方法。 不管这个属性或者方法是 private 还是 public 以及其他修饰符修饰的, 都能获取到, 这就是反射的强大之处。

反射技术是如何工作的?

我们都知道, java 文件经过编译, 会生成 class 字节码文件, 反射就是通过 class 字节码文件获取它里边的所有内容。
我们先了解如何通过构造函数创建对象:

对于获取 class 字节码文件, 我们有三种方式:

1.对象名.getCalss();

这个方法来自于 Object 对象已经存在的情况下, 可以使用这种方式
Class c1=foo1.getClass();
//Foo类的类类型

2.类名.class

类名.class 这是一个静态的属性, 只要知道类名, 就可以获取
如:Class c2=Foo.class;

1 2说明了如果知道了类,则直接.class,如果知道了对象,则直接.getClass()即可

####3.Class.forName(“com.wufang.Student” );(属于动态加载类)
如:
Class c3=null;
c3=Class.forName(“com.wufang.Student” )//有异常需要try-catch

注意:以上c1==c2==c3

举个例子

Student s = new Student();
Class clazz = s.getClass();
Class clazz3 = Class.forName("com.wufang.Student");

我们获取到了字节码文件,下一步我们就是通过字节码文件获取这个对象的所有东西。 例如创建对象, 属性, 方法等。

我们先了解如何通过构造函数创建对象

步骤:

1.获得 Class 对象
2 获得构造
3.通过构造对象获得实例化对象

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

    /*
    * 通过反射获取构造方法并使用
    * Constructor<?>[] getConstructors()
    * Constructor<T> getConstructor(Class<?>... parameterTypes)
    * T newInstance()
    * *
    Constructor:
    * T newInstance(Object... initargs)
    */
    public class ReflectDemo2 {
    public static void main(String[] args) throws ReflectiveOperationException {
//获取字节码文件
            Class clazz = Class.forName("com.wufang.Student");
//method(clazz);
//Constructor<T> getConstructor(Class<?>... parameterTypes)
//method2(clazz);
//method3(clazz);
//通过字节码文件获取对象
            Object obj = clazz.newInstance();
            System.out.println(obj);
        }

        private static void method3(Class clazz)
                throws NoSuchMethodException, InstantiationException, IllegalAccessException,
InvocationTargetException {
            Constructor c = clazz.getConstructor(String.class, int.class);//获取有参构造, 参数 1 类型为 String, 参数 2 类型为 int
            System.out.println(c);
            Object obj = c.newInstance("lisi", 30);
            System.out.println(obj);
        }

        private static void method2(Class clazz)
                throws NoSuchMethodException, InstantiationException, IllegalAccessException,
                InvocationTargetException {
            Constructor c = clazz.getConstructor();//获取无参构造
            System.out.println(c);
            Object obj = c.newInstance();
            System.out.println(obj);
        }

        private static void method(Class clazz) {
//Constructor<?>[] getConstructors() :获取所有 public 修饰的构造方法
            Constructor[] cs = clazz.getConstructors();
            for (int i = 0; i < cs.length; i++) {
                System.out.println(cs[i]);
            }
        }
    }

以上两种方法获取对象,一种是 newInstance(只能通过空参的构造方法创建对象), 一种是getConstructors


那我们如何获取类中用 private 修饰的成员变量和方法呢。反射机制给我们提供了一套可以获取私有的方法,我们称之为暴力反射。
暴力反射一共有 5 个步骤:

  1. 获取学生类字节码对象
  2. 获取学生对象
  3. 通过 getDeclaredField 方法获取私有字段
  4. 通过 setAccessible 让 jvm 不检查权限
  5. 通过 set 方法设置对象为具体的值
    给大家演示一下, 并做具体的说明:
   /*
    * 通过反射获取私有成员变量并使用
    * Field[] getDeclaredFields()
    * Field getDeclaredField(String name)
    */
    public class ReflectDemo4 {
        public static void main(String[] args) throws ReflectiveOperationException {
    //获取学生类的字节码对象
            Class clazz = Class.forName("com.wufang.Student");
    //获取学生对象
            Object stu = clazz.newInstance();
    //获取私有的字段对象
            Field f = clazz.getDeclaredField("name");
            f.setAccessible(true);//设置反射时取消 Java 的访问检查,暴力访问
            f.set(stu, "lisi");//设置
            Object name = f.get(stu);
            System.out.println(name);
        }
    }

上边讲的是如何获取成员变量, 我们在给大家讲一讲如何获取成员方法:

Class clazz = Class.forName("com.heima.Student");
// 创建学生对象
Object stu = clazz.newInstance();
// 暴力反射获取方法
Method method = clazz.getDeclaredMethod("method");
// 让 jvm 不检查权限
method.setAccessible(true);
// 执行方法
method.invoke(stu);

大家能看到, 获取成员方法的步骤和获取成员变量的步骤差不多, 都是先通过字节码文件获取对象, 再通过对象获取私有方法, 设置允许暴力访问权限, 执行方法。
上诉就是通过暴力反射来获取对象的私有的成员变量和成员方法。我们只有理解了反射的概念和用法才能更深刻的理解反射的意义。这样才有助于我们在实际工作中的开发中灵活运用反射技术来解决我们开发中的难题。


本文由 方方無 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论

shijiebei 365bet manbetx 188bet xinshui caipiao 95zz tongbaoyule beplay 88bifa 18luck betway bwin hg0088 aomenjinshayulecheng ca88 shenbotaiyangcheng vwin w88 weide