老司机带带你,教你学会Java中又骚又暴力的“反射”技术

news2024/9/25 17:19:05

在Java中有这么一个很骚的技术,几乎贯穿了所有主流的框架,在所有主流框架的底层中你都可以看见它的身影,这个技术就是反射。关于反射,有很多小白会觉得很难,搞不清楚到底是怎么回事,也不知道该怎么用,今天壹哥就来教教你如何理解和使用Java的反射。

一. 反射概念

我们知道,在物理层面上,反射是一种光学现象,是指光在传播到不同物质时,在分界面上改变传播方向后又返回原来物质中的现象。

而在Java中,反射是一种机制,而不是一种现象。反射机制指的是程序在运行时能够动态获取类对象的属性,和调用类对象的方法。

Java中的编译类型有两种:

静态编译:在编译时确定类型,绑定对象即通过。

动态编译:运行时确定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。

使用反射可以赋予 JVM 动态编译的能力,否则类的元数据信息只能用静态编译的方式实现。

二. 反射API
在Java中,JDK为我们提供了一些反射相关的API,如下表所示:

接下来我们就来看看反射到底怎么用。

三. 具体使用

下面用一个案例来让大家感受一下反射的牛逼之处。

1. 常规实现

我们知道,在Java中的实体类总会有一些固定的方法,比如每个属性的 get()、set()方法,还有初始化属性创建对象的构造方法,打印对象信息的toString()等方法。假如我们在没有使用注解的情况下,需要创建2个普通的实体类:Cat、Dog,代码如下所示:

 public class Cat {
    private String name;
    private int age;
 
    public Cat() {
    }
    
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class Dog{
    private String name;
    private int age;
 
    public Dog() {
    }
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

我们想在案例代码中创建对象并打印对象信息,如下所示:

public class Demo01 {
    public static void main(String[] args){
        Cat cat = new Cat("招财", 1);
        System.out.println(cat.toString());
 
        Dog dog = new Dog("旺财",2);
        System.out.println(dog.toString());
    }
}

在上面这两个实体类中,都存在着名字相同、但方法体不同的toString()方法。如果我们在实体类中不重写toString() ,直接通过对象调用 toString(),打印的结果不会是对象的信息。

我们可以使用反射给两个实体类,甚至更多的实体类自动加上toString()方法,从而达到减少代码量的目的。

2. 反射实现

2.1 创建父类BaseEntity

首先我们创建一个父类BaseEntity

public class BaseEntity {
    @Override
    public String toString() {
        //1.获取反射对象
        Class<? extends BaseEntity> clazz = this.getClass();
        //2.创建 StringBuffer 对象拼接字符串
        StringBuffer sb = new StringBuffer();
        //3.通过 getSimpleName() 获取类名并拼接
        sb.append(clazz.getSimpleName());
        //拼接大括号
        sb.append("{");
        //4.获取所有成员变量对象
        Field[] fields = clazz.getDeclaredFields();
        Object value = null;
        for (int i = 0; i < fields.length; i++) {
            //5.获取成员变量对象
            Field field = fields[i];
            //6.打开访问权限
            field.setAccessible(true);
            //7.通过 getName() 获取属性名并拼接
            sb.append(getName());
            sb.append("=");
            //8.通过 get() 传递 this 获取对象的属性值
            try {
                value = field.get(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            //9.判断是否为 String 类型的属性,是则添加单引号
            if(field.getType() == String.class){
                sb.append("'");
                sb.append(value);
                sb.append("'");
            }else{
                sb.append(value);
            }
            //10.判断是否为最后一个属性对象
            if(i == fields.length-1){
                sb.append("}");
            }else{
                sb.append(", ");
            }
        }
        //11.通过 toString() 转换成字符串并返回
        return sb.toString();
    }
}

2.2 继承父类

然后将两个实体类 Cat 和 Dog,都继承 BaseEntity且不重写 toString()方法。

public class Cat extends BaseEntity{
    private String name;
    private int age;
 
    public Cat() {
    }
    
    public Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
public class Dog extends BaseEntity{
    private String name;
    private int age;
 
    public Dog() {
    }
    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}

2.3 运行测试

接下来在案例类中创建对象并打印对象信息,这里会发现打印结果不再是之前没有 toString() 的情况,而是会分别打印出各自对象的信息。

public class Demo01 {
    public static void main(String[] args){
        Cat cat = new Cat("招财", 1);
        System.out.println(cat.toString());
 
        Dog dog = new Dog("旺财",2);
        System.out.println(dog.toString());
    }
}

我们可以在以上案例中发现,toString()方法在运行状态时,通过反射获取了运行对象的类属性,进行了信息的拼接,从而达到了减少实体类代码量的目的,提高了代码的复用性。

四. 小结

使用反射技术,可以让我们进行动态的创建对象和编译,体现出很高的代码灵活性。但反射技术却对性能有一定的影响,它不如静态创建对象那样来得直接高效。所以反射既有好处也有缺点,但好处远大于缺点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS Code快速实现Git PR操作

注意&#xff1a;建议先学习git的基本操作。 安装插件 下图中红圈标记的插件都安装好。 Fork上游仓库 在网页上点击你想要fork的仓库&#xff0c;点击fork 然后该仓库就会fork到你的github账户下面&#xff0c;如下图。 现在可以在你账户下面的repo&#xff08;我们称为下…

[附源码]Python计算机毕业设计Django和vue的茶文化交流平台的设计与实现

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Global Mapper 导出图层功能的妙用(重采样、设置文件类型、切片、按掩膜提取or裁剪……)

许多GIS软件都有导出的功能&#xff0c;但其中大部分的导出功能比较单一直接&#xff0c;仅仅是导出而已&#xff0c;或者最多可以改个导出的格式&#xff0c;改个坐标。但是Global Mapper 不一样&#xff0c;导出功能非常非常多&#xff0c;比如重采样&#xff08;可以设置重采…

Vue3框架的创建的两种种方案(第十二课)

1 VueCLi脚手架的安装 Home | Vue CLI (vuejs.org) 使用方法 | Yarn 中文文档 (bootcss.com) 3 Vite脚手架的安装 Vite | 下一代的前端工具链 4 使用的软件 Visual Studio Code webstorm64.exe IntelliJ IDEA 2022.2.3 HBuilder X 方案一 VueCLi脚手架的安装 1 创…

[附源码]计算机毕业设计在线招聘网站Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MobileViT

还是vit系列啊 只不过这次是Apple团队出的轻量级、通用且移动友好的网络框架 论文地址&#xff1a;https://arxiv.org/pdf/2110.02178.pdf 轻量级卷积神经网络 (CNN) 是移动视觉任务的事实。他们的空间归纳偏差使他们能够在不同的视觉任务中以较少的参数学习表示。 轻量级卷积…

微服务自动化【集群搭建】

目录 搭建 etcd 集群 etcd构建自身高可用集群主要有三种形式: 1. 静态部署(前提) 2. 集群搭建 3. 集群测试 搭建 etcd 集群 etcd构建自身高可用集群主要有三种形式: 静态发现:预先已知etcd集群中有哪些节点&#xff0c; 在启动时通过--initial-cluster参数直接指定好etc…

[附源码]JAVA毕业设计互联网保险网站(系统+LW)

[附源码]JAVA毕业设计互联网保险网站&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&a…

JavaWeb(一)

前言 首先深入了解之前&#xff0c;先回顾一些基础知识 C/S & B/S 就比如咱们日常生活中&#xff0c;咱们说的CF是cs游戏&#xff0c;这个cs是什么意思&#xff08;年幼的我也十分痴迷CF游戏&#xff0c;过去式了 hhh&#xff09;这里的cs可不是咱们说的csgo或者cs游戏。…

Vue 官方文档2.x教程学习笔记 1 基础 1.4 模板语法 1.4.1 插值

Vue 官方文档2.x教程学习笔记 文章目录Vue 官方文档2.x教程学习笔记1 基础1.4 模板语法1.4.1 插值1 基础 1.4 模板语法 【介绍】 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。 所有 Vue.js 的模板都是合法的 HTML&…

Flink SQL管理平台flink-streaming-platform-web安装搭建-整理

目录 步骤 安装 第二步 下载flink 第三步 安装flink-streaming-patform-web 第四步 配置flink web平台 第五步 运行demo 在Flink学习的入门阶段&#xff0c;非常重要的一个过程就是Flink环境搭建&#xff0c;这是认识FLInk框架的第一步&#xff0c;也是为后续的理论学习和…

全栈性能测试教程之性能测试理论(一) mockserver应用

1、mockServer 1.1什么是mockServer moco替代 Server服务 mocoServer即为测试替身的服务 主要针对于单元测试的应用&#xff0c;主要应用于解除单元测试之间的依赖 1.2mocoServer使用的场景 前端程序员 前端已经写好页面&#xff0c;但是后端的接口没有写好&#xff…

[Android]Mac电脑Android Studio使用真机调试运行

一、Mac电脑连接Android真机 我这里是一台中兴手机 1. 手机打开USB调试 打开“设置”找到“关于手机”进入&#xff0c;连续点击版本号&#xff0c;直到提示“您已经进入开发者模式”。回到“设置”找到“系统与更新”进入&#xff0c;再进入“开发者选项”&#xff0c;打开…

Vue笔记_03组件_mavonEditor组件(基于vue)

目录下载mavonEditor导入并注册mavonEditor组件[1] 全局注册[2]局部注册使用mavonEditor属性修改举例说明1-不展示预览分屏工具栏修改举例说明-根据配置显示工具栏编辑器插槽举例说明-自定义工具栏按钮函数监听下载mavonEditor 使用命令 npm install mavon-editor --s 进行下载…

Koa 6 响应(Response)

Koa Koa 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 6 响应(Response) 文章目录Koa6 响应(Response)6.1 APIStringBufferStreamObjectKoa Response 对象是在 node 的原生响应对象之上的抽象&#xff0c;提供了诸多对 HTTP 服务器开发有用的功能。 6…

Linux系统移植一:移植U-BOOT 添加自己的板子并编译(非petalinux版)

Linux系统移植流程 之前一直用官方给的Linux系统文件&#xff0c;没有自己系统地移植过&#xff0c;故整理一遍 不使用petalinux工具&#xff0c;尽管它提升了开发效率&#xff0c;但是不利于学习移植过程 嵌入式Linux系统移植主要由四大部分组成&#xff1a; 搭建交叉开发环…

【计算机网络】实验四 应用层和传输层协议分析(PacketTracer)

一.实验目的 通过本实验&#xff0c;熟悉PacketTracer的使用&#xff0c;学习在PacketTracer中仿真分析应用层和传输层协议&#xff0c;进一步加深对协议工作过程的理解。 二.实验内容 研究应用层和传输层协议 从 PC 使用 URL 捕获 Web 请求&#xff0c;运行模拟并捕获通信…

健身用什么耳机比较好、五款适合健身房运动的耳机推荐

大家都运动本身是一件特别枯燥无味的事情&#xff0c;尤其是一个人在健身房沉浸式撸铁的时候&#xff0c;而听音乐是大多数人缓解枯燥的首选&#xff0c;不过在健身的过程中拥有一款既要音质好、又要适合运动佩戴防水防汗的耳机可就不那么容易了。今天给大家推荐几款最佳的运动…

如何在lnmp中实现PHP多版本共存

背景&#xff1a;one框架需要swool扩展&#xff0c;同时php版本需要7.3&#xff0c;目前服务器安装的是lnmp1.6其中php5.6. 所以觉得安装一个php7.3作为切换版本 &#xff0c;以下是安装步骤 1.查找lnmp的install.sh文件&#xff0c;一般在/root/lnmp1.5/install.sh 下执行命令…

【Docker】Compose容器编排:微服务实战

Docker-Compose是Docker官方的开源项目&#xff0c; 负责实现对Docker容器集群的快速编排。是一个工具软件&#xff0c;可以 管理多个 Docker 容器 组成一个应用。你需要 定义一个 YAML 格式的配置文件docker-compose.yml &#xff0c;写好多个容器之间的调用关系。然后&#x…