zoukankan      html  css  js  c++  java
  • 【Java基础】Java中的反射机制

    一、反射的理解

    (1)正射

    在理解反射这个概念之前,我们先来理解Java中的“正射”。

    我们在编写代码时,当需要使用到某一个类的时候,必定先会去了解这是一个什么类,是用来做什么的,有怎么样的功能。

    之后我们才对这个类进行实例化,之后再使用这个类的实例化对象进行操作。

    Person person = new Person();
    person.sleep("8:00");

    (2)反射

    上面的栗子介绍了什么是“正射”,以及“正射”的一般代码实现;

    而反射则是在代码一开始编写时不知道要初始化的类是什么。因此,自然也无法使用new关键字来创建对象了。

    而当我们之后得到我们要初始化的类的名称及路径时,我们就可以使用JDK提供的反射API进行反射调用。

    Class clazz = Class.forName("com.test.domain.Person");
    Method method = clazz.getMethod("sleep", String.class);
    Constructor constructor = clazz.getConstructor();
    Object object = constructor.newInstance();
    method.invoke(object, "8:00");

    以上两段代码,其结果都是一样的,但是其实现的过程却有很大的差别:

    • 第一段代码在未运行前就已经确定了要运行的类(Person);
    • 第二段代码则是在整个程序运行时从某些地方(例:配置文件)获取到相应的字符串值才能知道要运行的类("com.test.domain.Person")。

    二、反射的应用

    在我们日常的生产环境中,很少会直接使用到反射,但这并不代表反射在实际应用中很少。相反反射在Java中的框架使用得十分的多,反射是框架设计的灵魂:

    ①:spring、hibernate中会使用到反射机制,最常见的就是使用XML配置文件获取对应的类,然后再加载;

    ②:真的好多啊。。。

    三、反射的常用函数

    (1)获取反射中的class对象

    在反射中,要获取一个类或调用一个类的方法,首先必须要获取到该类的对象,在Java API中,获取Class类对象三种方法:

    ①:Class.forName("类的路径名");

    Class clazz = Class.forName("com.test.domain.Person");

    ②:利用已有类对象的getClass()方法;

    Person person = new Person();
    Class clazz = person.getClass();

    ③:对于在编译前就已经知道的类,可以使用.class属性;

    Class clazz = Person.class;

    (2)通过反射创建类对象

    通过反射建立类的对象,Java API提供了两种方式:

    ①:通过class对象的newInstance()方法;

    Class clazz = Class.forName("com.test.domain.Person"); 
    Person person
    = (Person)clazz.newInstance();

    ②:通过Constructor对象的newInstance()方法;

    Class clazz = Class.forName("com.test.domain.Person");
    Constructor con = clazz.getConstructor();
    Person person = (Person)con.newInstance();

    (3)通过反射操作成员变量

    ①:获取所有成员getFields()&getDeclaredFields();

    使用getFields()方法可以获取Class类的成员变量,但是无法获取私有属性。

    Class clazz = Class.forName("com.test.domain.Person");
    Field[] fields = clazz.getFields();
    for (Field field : fields) {
      System.out.print(field.getName());
    }

    ②:获取单个成员getField()&getDeclared

    ③:修改成员变量的值set(Object obj, Object value)

    Class clazz = Class.forName("com.test.domain.Person");
    Person person = (Person)clazz.newInstance();
    Field field = clazz.getField("name");
    field.set(person, "张三");

    当属性为private时,这是我们无法直接使用set()方法修改它的值,此时应该使用setAccessible()方法取得访问权限:

    Class clazz = Class.forName("com.test.domain.Person");
    Person person = (Person)clazz.newInstance();
    Field field = clazz.getDeclaredField("name");
    field.setAccessible(true);
    field.set(person, "张三");

    (4)通过反射操作成员方法

    ①:获取所有方法getMethods()&getDeclaredMethods()

    ②:获取单个成员getMethod()&getDeclaredMethod()

    操作方法与操作变量相差不大,在获取到对应方法之后使用invoke()方法执行即可。同理,遇见私有方法时,也需要使用setAccessible(true)方法获取访问权限。

    Class clazz = Class.forName("com.test.domain.Person");
    Person person = (Person)clazz.newInstance();
    Method method = clazz.getMethod("setName", String.class);
    method.setAccessible(true);
    method.invoke("李四");

    通常情况下,即便得到的是当前类,private修饰的属性或方法也是没有权限访问的,你需要设置访问权限setAccessible(true)来取得访问权限,但在实际上,这已经破坏了规则,所以应该尽量少地使用。

  • 相关阅读:
    310. Minimum Height Trees -- 找出无向图中以哪些节点为根,树的深度最小
    297. Serialize and Deserialize Binary Tree *HARD*
    235.236. Lowest Common Ancestor of a Binary (Search) Tree -- 最近公共祖先
    222. Count Complete Tree Nodes -- 求完全二叉树节点个数
    208. Implement Trie (Prefix Tree) -- 键树
    excel函数累加求和与累计百分比应用
    js去除空格
    js获取标签下标
    js中对String去空格
    css的三种使用方式:行内样式,内嵌样式,外部引用样式
  • 原文地址:https://www.cnblogs.com/jojop/p/10668239.html
Copyright © 2011-2022 走看看