【数据结构】(12) 反射、枚举、lambda 表达式

一、反射

1、反射机制定义及作用

        反射是允许程序在运行时检查和操作类、方法、属性等的机制,能够动态地获取信息、调用方法等。换句话说,在编写程序时,不需要知道要操作的类的具体信息,而是在程序运行时获取和使用。

2、反射机制的原理

        程序运行时,JVM编译好的 .class 文件(代表一个类)解析为 java.lang.Class 类的实例,这个实例包含了该类的所有信息。通过反射机制,可以用到这个实例,来获取该类的信息并进行操作

        下面介绍反射的相关类。以 Student 类为例子:

public class Student {
    //私有属性name
    private String name = "小帅";
    //公有属性age
    public int age = 18;
    //不带参数的构造方法
    public Student(){
        System.out.println("Student()");
    }

    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }

    private void eat(){
        System.out.println("i am eat");
    }

    public void sleep(){
        System.out.println("i am pig");
    }

    private void function(String str) {
        System.out.println(str);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

        Class 在 java.lang 中,不需要导包。其它三个都在 java.lang.reflect 中。

3、Class 类

        代表类的实体

        获取 JVM 给类解析的 Class 对象:

        其它方法:

4、Field 类

        代表类的属性

  • getField(String name):获得指定公有属性对象。
  • getField():获得所有公有属性对象。
  • getDeclaredField(String name):获得某个属性对象。(不限于公有)
  • getDeclaredField():获得所有属性对象。

        属性对象.get(对象) 表示获取指定对象的某属性,静态属性不需对象,参数填 null。

5、Method 类

        代表类的方法

6、Constructor 类

        代表类的构造方法

        利用构造方法对象获得类的实例:

7、使用反射动态加载类并创建对象

        编写一个程序,在运行时根据用户输入的类名来动态加载类并创建对象,调用其 draw 方法。

import java.util.Scanner;

// 定义一个 Shape 接口
interface Shape {
    void draw();
}

// 定义 Circle 类实现 Shape 接口
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制一个圆形");
    }
}

// 定义 Rectangle 类实现 Shape 接口
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("绘制一个矩形");
    }
}

public class DynamicClassLoadingExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入要加载的类名(如 Circle 或 Rectangle):");
        String className = scanner.nextLine();

        try {
            // 根据用户输入的类名获取 Class 对象
            Class<?> clazz = Class.forName(className);
            // 创建该类的实例
            Shape shape = (Shape) clazz.getDeclaredConstructor().newInstance();
            // 调用 draw 方法
            shape.draw();
        } catch (Exception e) {
            e.printStackTrace();
        }
        scanner.close();
    }
}

反射优点:让程序更灵活,动态加载类和方法、可以访问和修改私有成员。

反射缺点:性能开销大、破坏封装性和安全性、程序不易读。

二、枚举

1、定义及作用

        一组常量,比如颜色,它们是同一类,我们想把这组常量组织在一起,就用枚举。作用是与没有意义的数字区分开来(如果定义一组常量,就要用数字表示它们)。例子:

public enum Color {
    RED, GREEN, BLUE;
    public static void main(String[] args) {
        Color color = Color.BLUE;
        switch (color) {
            case RED:
                System.out.println("RED");
                break;
            case GREEN:
                System.out.println("GREEN");
                break;
            case BLUE:
                System.out.println("BLUE");
                break;
            default:
                System.out.println("default");
                break;
        }
    }
}

        枚举类默认继承了 java.lang.Enum。枚举常量的默认是 public static final 修饰

2、常用方法

        枚举类型能够使用这些方法,是因为默认继承了 Enum 类:

        但是可以发现,Enum 类中没有 values 方法。这是因为自定义枚举类型中枚举常量的数量、类型都是不确定的,如果 values 封装在 Enum 类中,就需要在运行时动态确定每个枚举常量(需要用到反射,破坏了封装性、增强了复杂性等)。实际上,编译器编译时会为每个枚举类型自动加上 values 方法,返回的数组在编译时就确定

3、构造方法

        枚举相当于是类,可以有属性、构造方法、方法。构造方法默认私有,且只能。这样保证了枚举实例的唯一性。

 查看构造函数的实际参数有哪些:

        多了 String 和 int 类型参数,因为枚举类默认继承了 Enum,其本身有 name 和 ordinal 属性,隐藏了 super(name, ordinal) ,所以 Color 构造函数会多 2 个参数

4、枚举和反射

        通过反射获取枚举类的实例:

         出现错误:

       查看 newInstance 源码:

        因此,不能通过反射创建枚举类的实例。这样设计的目的是让枚举类只有一个实例防止反射攻击由私有构造函数、防反射攻击这两个特点得知,枚举实现单例模式(一种创建型模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例)是安全的

枚举优点:简单安全。

枚举缺点:不能继承

5、枚举实现单例模式

        后续学了单例模式补充。

三、Lambda 表达式

1、定义及作用

        相当于方法,但是比方法更简化。语法:

(形参列表)->表达式

(形参列表)->{代码块}

// 参数类型可以省略(要省全都省),只有一个参数可以省略圆括号。

// 返回一个值或者不返回值

// 只有一条 return 语句,可省略 return

2、函数式接口

  • 函数式接口:一个接口只有一个抽象方法
  • @FunctionalInterface 注解:以函数式接口的标准(只有一个抽象方法)要求接口,检查作用。
  • lambda 可简化匿名内部,实现函数式接口

        几个函数式接口代码:

//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}

        使用匿名内部类实现接口,重写方法:

        使用 lambda 实现接口,重写方法:

NoParameterNoReturn noParameterNoReturn = ()->{System.out.println("hello");};

3、变量捕获

        匿名内部类中可捕获外部变量。如果想修改捕获的变量,那该变量必须被 final 修饰,否则报错。lambda 表达式同理

        int a = 10;
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
//                a = 99;  不允许修改未被 final 修饰的外部变量
                System.out.println(a); // 变量 a 捕获
                return o1.compareTo(o2);
            }
        });

4、Lambda 在集合中的应用

        lambda 表达式作为以上方法的参数,实现接口中的方法。 

4.1、Collection 接口

        以 forEach 为例:

        源码如下:Consumer 是函数式接口,accept 是实现的抽象方法。

        实现函数式接口:

4.2、List 接口

        以 sort 为例:

        源码:

        在 Java 中,所有类都直接或间接地继承自 Object 类,因此,Comparator 接口继承了 Object 类的 equals 方法。它不是 Comparator 接口自身定义的抽象方法,因此,不违反函数式接口的定义规则。

    @FunctionalInterface
    public interface Comparator<T> {
        int compare(T o1, T o2);

        boolean equals(Object obj); // 继承自 Object,不影响函数式接口
        
        ......
    }

        实现:

4.3、Map 接口

        以 forEach 为例:

        源码:

        实现:

5、总结:

优点:语句简洁、方便函数式编程(替换匿名内部类)、改善集合操作。

缺点:可读性差、不易调试。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【初探数据结构】时间复杂度和空间复杂度

&#x1f4ac; 欢迎讨论&#xff1a;在阅读过程中有任何疑问&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果你觉得这篇文章对你有帮助&#xff0c;记得点赞、收藏&#xff0c;并分享给更多对数据结构感…

基于 MySQL 递归 CTE 实现表,父级id与子级id拼接

1、函数 xr_test.tb_content替换成自己的表 CREATE DEFINERroot% FUNCTION get_related_ids(start_id BIGINT) RETURNS varchar(1000) CHARSET utf8mb4 COLLATE utf8mb4_general_ciDETERMINISTIC BEGINDECLARE result_ids VARCHAR(1000);-- 使用递归 CTE 查找所有相关的 idWI…

Redission可重试、超时续约的实现原理(源码分析)

Redission遇到其他进程已经占用资源的时候会在指定时间waitTime内进行重试。实现过程如下&#xff1a; 执行获取锁的lua脚本时&#xff0c;会返回一个值&#xff0c; 如果获取锁成功&#xff0c;返回nil&#xff0c;也就是java里的null 如果获取锁失败&#xff0c;用语句“PT…

ue----git局域网内部署裸仓库,别的机器进行访问

最近由于经常迁移项目到另一台机器上进行部署更新一点就要整个迁移 弄得麻烦了 就在网上学了一下这个方式 首先我们在想要建立裸仓库的电脑上找到一个文件夹放置我们的裸仓库 在此点击鼠标右键选择 open git bash here 输入命令 创裸仓库 git init --bare gitTestName.git…

输入搜索、分组展示选项、下拉选取,el-select 实现:即输入关键字检索,返回分组选项,选取跳转到相应内容页 —— VUE 项目-全局模糊检索

后端数据代码写于下一篇&#xff1a;输入搜索、分组展示选项、下拉选取&#xff0c;全局跳转页&#xff0c;el-select 实现 —— 后端数据处理代码&#xff0c;抛砖引玉展思路 【效果图】&#xff1a;分组展示选项 >【提供界面操作体验】 【录制效果视频展示】&#xff1a…

【UCB CS 61B SP24】Lecture 11 - Inheritance 4: Iterators, Object Methods学习笔记

本文内容为集合&#xff08;Set&#xff09;的介绍与使用&#xff0c;并通过数组手动实现集合&#xff0c;接着介绍了迭代器&#xff0c;使用迭代器我们能够更方便地遍历集合中的元素。 1. Set 1.1 Set介绍与Java实现类的使用 集合&#xff08;Set&#xff09;是一种常见的数…

玩机日记 12 fnOS使用lucky反代https转发到外网提供服务

目录 1、安装lucky 2、更新lucky 3、上传ssl证书 4、设置安全入口&#xff0c;替换fnOS的应用url 5、添加https反代 这一篇主要是解决一下飞牛反代https的问题。可以先看玩机日记 12.5 在PVE Windows11上部署本地AI模型&#xff0c;使用群晖反代https转发到外网提供服务&a…

神经网络八股(3)

1.什么是梯度消失和梯度爆炸 梯度消失是指梯度在反向传播的过程中逐渐变小&#xff0c;最终趋近于零&#xff0c;这会导致靠前层的神经网络层权重参数更新缓慢&#xff0c;甚至不更新&#xff0c;学习不到有用的特征。 梯度爆炸是指梯度在方向传播过程中逐渐变大&#xff0c;…

【ARM】MDK如何生成指定大小的bin文件,并指定空区域的填充数据

1、 文档目标 解决MDK如何生成指定大小的bin文件&#xff0c;并指定空区域的填充数据 2、 问题场景 客户有这样的需求&#xff0c;客户本身的工程编译生成bin文件后&#xff0c;bin文件大小为200k。整体芯片的内存有512k。客户想要最终生成的bin文件可以达到512k的一个情况&a…

Linux-----进程间通信

一、按通信范围分类 同一主机进程通信 传统IPC方式&#xff1a; 管道&#xff08;无名管道、有名管道&#xff09;信号&#xff08;Signal&#xff09; System V IPC&#xff1a; 共享内存&#xff08;效率最高&#xff09;消息队列信号量 POSIX IPC&#xff08;较新标准&#…

Part 3 第十二章 单元测试 Unit Testing

概述 第十二章围绕单元测试展开&#xff0c;阐述了单元测试的实践与重要性&#xff0c;通过对比其他测试类型&#xff0c;突出其特点&#xff0c;还介绍了单元测试的最佳实践、避免的反模式以及与测试替身相关的内容&#xff0c;为编写高质量单元测试提供指导。 章节概要 1…

Windows10配置C++版本的Kafka,并进行发布和订阅测试

配置的环境为&#xff1a;Release x64下的环境 完整项目&#xff1a;https://gitee.com/jiajingong/kafka-publisher 1、首先下载相应的库文件&#xff08;.lib&#xff0c;.dll&#xff09; 参考链接&#xff1a; GitHub - eStreamSoftware/delphi-kafka GitHub - cloade…

Deepseek引爆AI热潮 防静电地板如何守护数据中心安全

近期&#xff0c;Deepseek的爆火将人工智能推向了新的高度&#xff0c;也引发了人们对AI背后基础设施的关注。作为AI运行的“大脑”&#xff0c;数据中心承载着海量数据的存储、处理和传输&#xff0c;其安全稳定运行至关重要。而在这背后&#xff0c;防静电地板扮演着不可或缺…

Spring框架基本使用(Maven详解)

前言&#xff1a; 当我们创建项目的时候&#xff0c;第一步少不了搭建环境的相关准备工作。 那么如果想让我们的项目做起来方便快捷&#xff0c;应该引入更多的管理工具&#xff0c;帮我们管理。 Maven的出现帮我们大大解决了管理的难题&#xff01;&#xff01; Maven&#xf…

QSplashScreen --软件启动前的交互

目录 QSplashScreen 类介绍 使用方式 项目中使用 THPrinterSplashScreen头文件 THPrinterSplashScreen实现代码 使用代码 使用效果 QSplashScreen 类介绍 QSplashScreen 是 Qt 中的一个类&#xff0c;用于显示启动画面。它通常在应用程序启动时显示&#xff0c;以向用户显…

【Vscode 使用】集合1

一、使用make工具管理工程 windows下&#xff0c;下载mingw64&#xff0c;配置好mingw64\bin 为 Win10系统全局变量后。 在mingw64/bin目录下找到mingw32-make.exe工具。复制一份改名为&#xff1a;make.exe&#xff0c;没错&#xff0c;就是那么简单&#xff0c;mingw64自带m…

PHP-create_function

[题目信息]&#xff1a; 题目名称题目难度PHP-create_function2 [题目考点]&#xff1a; create_function ( string args , string args , string code )[Flag格式]: SangFor{wWx5dEGHHhDUwmST4bpXwfjSzq43I6cz}[环境部署]&#xff1a; docker-compose.yml文件或者docker …

golang内存泄漏

golang也用了好几年了&#xff0c;趁着有空 整理归纳下&#xff0c;以后忘了好看下 一般认为 Go 10次内存泄漏&#xff0c;8次goroutine泄漏&#xff0c;1次是真正内存泄漏&#xff0c;还有1次是cgo导致的内存泄漏 1:环境 go1.20 win10 2:goroutine泄漏 单个Goroutine占用内存&…

Python Seaborn库使用指南:从入门到精通

1. 引言 Seaborn 是基于 Matplotlib 的高级数据可视化库,专为统计图表设计。它提供了更简洁的 API 和更美观的默认样式,能够轻松生成复杂的统计图表。Seaborn 在数据分析、机器学习和科学计算领域中被广泛使用。 本文将详细介绍 Seaborn 的基本概念、常用功能以及高级用法,…

修改与 Git 相关的邮箱

要修改与 Git 相关的邮箱信息&#xff0c;需要区分以下两种情况&#xff1a; 1. 修改 Git 提交时使用的邮箱&#xff08;影响提交记录&#xff09; Git 提交记录中的邮箱由本地 Git 配置的 user.email 决定&#xff0c;与 SSH 密钥无关。修改方法如下&#xff1a; 全局修改&a…