一篇文章带你搞定JAVA反射

目录
  • 1、反射的概念
    • 1、概念
  • 2、获取字节码文件对象的方式
    • 2.1 元数据的概念
    • 2.2 获取class对象的方式
    • 1、访问权限
    • 2、获取方法
      • 2.1 访问静态方法
      • 2.2 访问类方法
      • 3、获取字段,读取字段的值
    • 4、获取实现的接口
    • 5、获取构造函数,创建实例
    • 6、获取继承的父类
    • 7、获取注解
  • 4、反射实例
  • 5、总结

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类对象分别获取类的构造函数、方法&属性的具体信息,并进行后续操作。

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

(0)

相关推荐

  • Java开发反射机制的实战经验总结

    目录 前言 一.创建Class的三种方式 二.反射获取类的所有属性和属性类型 三.反射动态修改类属性的注解值 四.反射获取类的方法及调用方式 总结 前言 我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用. 存在这样一个类: package com.example.demo; import com.alibaba.fastjson.annotation.JSONField; public class User { private String name; @

  • Java开发岗位面试被问到反射怎么办

    目录 到底什么是反射呢??? 2. 类的生命周期 3. Java反射框架主要提供以下功能: 反射的基本用法 1. 获得Class对象 2. 判断是否为某个类的实类 3.创建实例 4. 获取构造器信息 5. 获取方法 6. 获取类的成员变量(字段)信息 7. 利用反射创建数组 反射的注意事项 反射的主要用途 总结 到底什么是反射呢??? 反射的核心就是JVM在运行时才动态加载类或调用方法,访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁. 每一个类都会产生一个对应的Class对象,也

  • Java反射机制的简单讲解

    🌱1. 什么是反射机制? 首先大家应该先了解两个概念,编译期和运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制 简单说,反射机制值得是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息. 🌱2. java反射机制提供了什么功能? 在运行时能够判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调用任一对象的方法 在运行时创建新类对象 🌱3.new和反射创建有什么区别呢? ne

  • Java的枚举,注解和反射(二)

    目录 反射 什么是反射? 反射的用途 反射的具体作用 反射的主要API Class类 总结 反射 什么是反射? 反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性.反射被视为动态语言的关键. //在反射之前可以做的事情 @Test public void Test1() { //创建Person类的对象 Person person = new Person("name", 78); //通过对象调用其内部的方法

  • Java通过反射,如何动态修改注解的某个属性值

    Java反射动态修改注解的某个属性值 昨晚看到一条问题,大意是楼主希望可以动态得建立多个Spring 的定时任务. 这个题目我并不是很熟悉,不过根据题目描述和查阅相关Spring 创建定时任务的资料,发现这也许涉及到通过Java代码动态修改注解的属性值. 今天对此尝试了一番, 发现通过反射来动态修改注解的属性值是可以做到的: 众所周知,java/lang/reflect这个包下面都是Java的反射类和工具. Annotation注解,也是位于这个包里的.注解自从Java 5.0版本引入后,就成为

  • 一篇文章带你搞定JAVA反射

    目录 1.反射的概念 1.概念 2.获取字节码文件对象的方式 2.1 元数据的概念 2.2 获取class对象的方式 1.访问权限 2.获取方法 2.1 访问静态方法 2.2 访问类方法 3.获取字段,读取字段的值 4.获取实现的接口 5.获取构造函数,创建实例 6.获取继承的父类 7.获取注解 4.反射实例 5.总结 1.反射的概念 1.概念 反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法

  • 一篇文章带你搞定JAVA注解

    目录 1.注解是什么 2.jdk支持的注解有哪些 2.1 三种常用的注解: 2.2 元注解 3.注解实例 1.自定义注解 2.在对应的方法上增加注解 3.在项目启动的时候检查注解的枚举 4.总结 1.注解是什么 Java 注解用于为 Java 代码提供元数据,看完这句话也许你还是一脸懵逼,用人话说就是注解不直接影响你的代码执行,仅提供信息.接下我将从注解的定义.元注解.注解属性.自定义注解.注解解析JDK 提供的注解这几个方面再次了解注解(Annotation) 2.jdk支持的注解有哪些 2.

  • 一篇文章带你搞定JAVA泛型

    目录 1.泛型的概念 2.泛型的使用 3.泛型原理,泛型擦除 3.1 IDEA 查看字节码 3.2 泛型擦除原理 4.?和 T 的区别 5.super extends 6.注意点 1.静态方法无法访问类的泛型 2.创建之后无法修改类型 3.类型判断问题 4.创建类型实例 7.总结 1.泛型的概念 泛型的作用就是把类型参数化,也就是我们常说的类型参数 平时我们接触的普通方法的参数,比如public void fun(String s):参数的类型是String,是固定的 现在泛型的作用就是再将St

  • 一篇文章带你搞定JAVA Maven

    目录 1.maven是什么,为什么存在?项目结构是什么样子,怎么定位jar 2.Idea 的操作 1.新建maven项目 2.配置仓库 3.添加依赖,添加fastjson的依赖 4.打包项目 3.Maven坐标主要组成 4.maven生命周期 4.1 名词解释 4.2 生命周期 4.3 goal 的概念 4.4 生命周期和phase的关系 5.idea maven的配置 6.POM有2个很重要的关系:聚合.继承 一.聚合 二.继承 7.Maven 中的 profile 8.maven 插件 9.

  • 一篇文章带你搞定JAVA内存泄漏

    目录 1.什么是内存泄漏 2.内存泄漏的原因 3.内存泄漏有哪些情况 3.1 代码中没有及时释放,导致内存无法回收. 3.2 资源未关闭造成的内存泄漏 3.3 全局缓存持有的对象不使用的时候没有及时移除,导致一直在内存中无法移除 3.4 静态集合类 3.5 堆外内存无法回收 4.内存泄漏的解决办法 5.内存问题排查 第一步 首先确认逻辑问题 第二步:分析gc是否正常执行 第三步 确认下版本新增代码的改动,尽快从代码上找出问题. 第四步:开启各种命令行和 导出 dump 各种工具分析 总结: 1.

  • 一篇文章带你搞定 springsecurity基于数据库的认证(springsecurity整合mybatis)

    一.前期配置 1. 加入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> &

  • 一篇文章带你搞定SpringBoot中的热部署devtools方法

    一.前期配置 创建项目时,需要加入 DevTools 依赖 二.测试使用 (1)建立 HelloController @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "hello devtools"; } } 对其进行修改:然后不用重新运行,重新构建即可:只加载变化的类 三.热部署的原理 Spring Boot 中热部

  • 一篇文章带你搞定SpringBoot不重启项目实现修改静态资源

    一.通过配置文件控制静态资源的热部署 在配置文件 application.properties 中添加: #表示从这个默认不触发重启的目录中除去static目录 spring.devtools.restart.exclude=classpath:/static/** 或者使用: #表示将static目录加入到修改资源会重启的目录中来 spring.devtools.restart.additional-paths=src/main/resource/static 此时对static 目录下的静态

  • 一篇文章带你搞定Ubuntu中打开Pycharm总是卡顿崩溃

    由于 Ubuntu 中的汉字输入实在是太不友好了,所以装了个 搜狗输入法,好不容易把 搜狗输入法装好,本以为可以开开心心的搞代码了,然而... pycharm 一打开,就崩溃,关不掉,进程杀死还是不行,只能关机重启. 本以为 pycharm 出现了问题,又重装了两遍,还是不行. 最终发现竟然是搜狗输入法以及 fcitx 输入法的锅 唉,只能老老实实的把 fctix 和搜狗输入法卸载了: (1)Ubuntu 软件里卸载 fctix,然后将键盘输入法系统改成 IBus (2)卸载搜狗输入法 先查找软

  • 一篇文章带你搞定Python多进程

    目录 1.Python多进程模块 2.Python多进程实现方法一 3.Python多进程实现方法二 4.Python多线程的通信 5.进程池 1.Python多进程模块 Python中的多进程是通过multiprocessing包来实现的,和多线程的threading.Thread差不多,它可以利用multiprocessing.Process对象来创建一个进程对象.这个进程对象的方法和线程对象的方法差不多也有start(), run(), join()等方法,其中有一个方法不同Thread线

随机推荐