一篇文章带你搞定JAVA反射

 更新时间:2021年07月14日 17:09:43   作者:香菜聊游戏  
这篇文章主要介绍了Java反射机制的简单讲解,本文讲解了Java的高级概念反射机制,通过文字介绍案例该项概念和代码的详细展示,需要的朋友可以参考下

1、反射的概念

1、概念

反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能,叫做java语言的反射机制。反射很强大,有优点也有缺点。

优点:灵活性高。因为反射属于动态编译,即只有到运行时才动态创建 &获取对象实例。

缺点:执行效率低。

2、获取字节码文件对象的方式

2.1 元数据的概念

元数据(metadata):元数据是指用来描述类的数据,就是class的代码数据。所有的class文件加载到虚拟机之后都会被构建成class对象,class对象描述了一个类都有哪些东西,大家都知道的实现的接口,继承的抽象类,成员变量,类变量,成员方法,类方法,静态方法等,这个class对象就是元数据。

  • Class类:代表一个类。
  • Field类:代表类的成员变量(成员变量也称为类的属性)。
  • Method类:代表类的方法。
  • Constructor类:代表类的构造方法。

图片

2.2 获取class对象的方式

  • 通过对象获得,因为任何对象都必须和class对象关联
  • 通过类对象直接获得
  • 通过类加载器获得,因为类加载器读取class文件会返回class对象

即将用来反射的对象(随便定义的一个对象,只是为了演示)

package org.pdool.reflect;
 
/**
* @author 香菜
*/
public class Npc {
  // 静态field
  public static int NPC_TYPE_1 = 1;
  // 私有成员变量
  private int npcType;
  // 共有成员变量
  public String name;
  // 无参构造函数
  public Npc() {
  }
  // 有参构造函数
  public Npc(int npcType, String name) {
      this.npcType = npcType;
      this.name = name;
  }
 
  public int getNpcType() {
      return npcType;
  }
 
  public void setNpcType(int npcType) {
      this.npcType = npcType;
  }
 
  public String getName() {
      return name;
  }
 
  public void setName(String name) {
      this.name = name;
  }
  // 静态方法
  public static void sayHello(String word){
      System.out.println("hello " + word);
  }
}

获取反射class的三种方式

package org.pdool.reflect;
 
/**
* @author 香菜
*/
public class ClazzTest {
   public static void main(String[] args) {
       //第一种方式获取Class对象
       Npc npc1 = new Npc();//这一new 产生一个Npc对象,一个Class对象。
       Class npcClazz1 = npc1.getClass();//获取Class对象
       System.out.println(npcClazz1.getName());
 
       //第二种方式获取Class对象
       Class npcClazz2 = Npc.class;
       System.out.println(npcClazz1 == npcClazz2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
 
       //第三种方式获取Class对象
       try {
           Class npcClazz3 = Class.forName("org.pdool.reflect.Npc");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
           System.out.println(npcClazz3 == npcClazz2);//判断三种方式是否获取的是同一个Class对象
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }
 
  }
}

1、访问权限

反射机制的默认行为受限于Java的访问控制,可通过 setAccessible 绕过控制。

// 设置对象数组可访问标志
static void setAccessible(AccessibleObject[] array, boolean flag)  

2、获取方法

图片

2.1 访问静态方法

public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException, IllegalAccessException {
       Npc npc = new Npc(1, "妖神·凰女");
       Class npcClazz = Npc.class;
       // 第一个参数是方法名,第二个参数是函数的参数class对象,因为存在重载的可能性,用参数类型区分
       Method sayHello = npcClazz.getMethod("sayHello", String.class);
       sayHello.invoke(npc, "world");
  }

2.2 访问类方法

      Npc npc = new Npc(1, "妖神·凰女");
      System.out.println(npc.getName());
      Class npcClazz = Npc.class;
      // 第一个参数是方法名,第二个参数是函数的参数class对象,因为存在重载的可能性,用参数类型区分
      Method sayHello = npcClazz.getMethod("setName", String.class);
      sayHello.invoke(npc, "world");
      System.out.println(npc.getName());

 3、获取字段,读取字段的值

图片

       Npc npc = new Npc(1, "妖神·凰女");
       Class npcClazz = Npc.class;
       // 获取字段,并设置可访问
       Field field = npcClazz.getField("name");
       field.setAccessible(true);
       System.out.println( field.get(npc));

4、获取实现的接口

图片

5、获取构造函数,创建实例

图片

    Class npcClazz = Npc.class;
               Constructor declaredConstructor = npcClazz.getDeclaredConstructor(int.class,String.class);
       Npc npc = (Npc) declaredConstructor.newInstance(1, "妖神");
       System.out.println(npc.getName());

6、获取继承的父类

Class npcClazz = Npc.class;
Class superclass = npcClazz.getSuperclass();
System.out.println(superclass.getName());

7、获取注解

Class npcClazz = Npc.class;
       Annotation[] annotations = npcClazz.getAnnotations();
// 运行时注解
       for (Annotation annotation : annotations) {
           System.out.println(annotation.getClass().getName());
      }

4、反射实例

获取到元数据不是最终的目的,我们最终的目的是想在运行时去调用,访问类。说了太多,还是举个例子,大家都知道Spring的IOC,怎么实现的呐?

过程:

1、Spring 在项目启动的时间通过读取xml中配置的bean的路径,

2、然后通过Class.forName 读取class 到类加载器,

3、然后通过反射创建所有的bean实例并保存到容器中,启动容器之后,

4、在项目中可以直接获取bean对象。

我们来大概实现这一过程,因为xml的读取比较麻烦,直接用property来代替了。大家体会一下思想就可以了。

package org.pdool.reflect;
 
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
 
/**
* @author 香菜
*/
public class ClazzTest {
  public static void main(String[] args){
      try {
          Map<String,Object> container = new HashMap<>();
          //1.读取配置
          InputStream in = ClazzTest.class.getResourceAsStream("/beans.properties");
          Properties property = new Properties();
          property.load(in);
          //2.反射创建对象
          Set<Object> keySet = property.keySet();
          for (Object key : keySet) {
              // 2.1 获取类的全路径
              String classStr = (String) property.get(key);
              // 2.2 加载class 到虚拟机
              Class<?> beanClazz = Class.forName(classStr);
              // 2.3 获取缺省的构造函数
              Constructor<?> declaredConstructor = beanClazz.getDeclaredConstructor();
              // 2.4 创建实例
              Object o = declaredConstructor.newInstance();
              container.put((String) key,o);
          }
          // 3.获取实例
          Npc npc = (Npc) container.get("npc");
          System.out.println(npc == null);
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
}

5、总结

在使用Java反射机制时,主要步骤包括:

获取 目标类型的Class对象

通过 Class 对象分别获取Constructor类对象、Method类对象 或者 Field 类对象

通过 Constructor类对象、Method类对象 & Field类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作。

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • 浅谈Java设计模式之开放封闭原则

    浅谈Java设计模式之开放封闭原则

    本篇文章主要介绍了浅谈Java设计模式之开放封闭原则,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • MyBatis-Plus实现逻辑删除功能解析

    MyBatis-Plus实现逻辑删除功能解析

    这篇文章主要介绍了MyBatis-Plus实现逻辑删除功能解析,有时候并不需要真正的删除数据,而是想逻辑删除,方便数据恢复,MyBatis-Plus可以很方便的实现逻辑删除的功能,需要的朋友可以参考下
    2023-11-11
  • 一文了解mybatis的延迟加载

    一文了解mybatis的延迟加载

    本文主要为大家详细介绍下mybatis的延迟加载,从原理上介绍下怎么使用、有什么好处能规避什么问题。感兴趣的小伙伴可以跟随小编一起学习一下
    2022-07-07
  • java并发使用CountDownLatch在生产环境翻车剖析

    java并发使用CountDownLatch在生产环境翻车剖析

    这篇文章主要为大家介绍了java并发使用CountDownLatch在生产环境翻车的示例剖析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • JAVA爬虫实现自动登录淘宝

    JAVA爬虫实现自动登录淘宝

    给大家分享一个关于JAVA爬虫的相关知识点,通过代码实现自动登录淘宝网,有兴趣的朋友测试下。
    2018-04-04
  • Java MyBatis传出参数resultType和resultMap解读

    Java MyBatis传出参数resultType和resultMap解读

    这篇文章主要介绍了Java MyBatis传出参数resultType和resultMap解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • Java中用户向系统传递参数的三种基本方式实例分享

    Java中用户向系统传递参数的三种基本方式实例分享

    这篇文章主要介绍了Java中用户向系统传递参数的三种基本方式实例,有需要的朋友可以参考一下
    2014-01-01
  • 使用FeignClient设置动态Url

    使用FeignClient设置动态Url

    这篇文章主要介绍了使用FeignClient设置动态Url方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java8 Collectors.toMap的坑

    Java8 Collectors.toMap的坑

    这篇文章主要介绍了Java8 Collectors.toMap的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • spring学习之参数传递与检验详解

    spring学习之参数传递与检验详解

    这篇文章主要给大家介绍了关于spring参数传递与检验的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作能带来一定的帮助,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-07-07

最新评论