数据结构(Java):反射枚举Lambda表达式

news2024/11/25 9:41:58

目录

1、反射

1.1 反射的定义

1.2 反射机制的原理

1.3 反射相关类

1.4 Class类

1.4.1 相关方法

1.4.1.1 常用获得类相关的方法

​编辑

1.4.1.2 常用获得类中属性相关的方法

 1.4.1.3 获得类中构造器相关的方法

  1.4.1.4 获得类中方法相关的方法

1.4.2 获取Class对象

1.5 总结

1.6 代码实例

2、枚举

2.1 定义

2.1.1 简单使用

2.2 常用方法

2.3 构造方法

2.4 枚举和反射(阿里面试:为什么枚举实现单例模式是安全的?)

 2.5 总结

3、Lambda表达式

3.1 定义

3.2 函数式接口

3.3 省略规则

3.4 变量捕获

 3.5 Lambda表达式在集合中的使用

3.5.1 forEach循环

3.5.1.1 Collection集合

3.5.1.2 Map集合

3.5.2 sort排序-forEach循环

3.5.2.1 List集合


1、反射

1.1 反射的定义

Java的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任 意一个对象,都能够调用它的任意方法和属性,也能够修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

简单来说,反射就是在运行的状态下,能够看清类的基本信息。

我们可以这样理解:在安检时,我们把行李箱放在安检的机器上,这时,不管行李箱里面有什么东西,哪怕是私密的东西,也可以被看的一清二楚。

1.2 反射机制的原理

一个.java文件经过编译会生成.class字节码文件,在运行时,这个字节码文件又会被JVM解析成一个Class类的对象,程序在运行时,每个java文件最终就会变成Class类对象的一个实例,我们就可以通过这个Class类来获取或修改类的基本信息。

也就是说,在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象(见下文),然后通过Class对象的核心方法,达到反射的目的, 

1.3 反射相关类

要想实现反射,我们必须了解以下类: 

  • Class类:代表类的实体,在运行的Java应用程序中表示类和接口
  • Field类:代表类的成员变量/类的属性
  • Method类:代表类的方法
  • Constructor类:代表类的构造方法

1.4 Class类

1.4.1 相关方法

1.4.1.1 常用获得类相关的方法

1.4.1.2 常用获得类中属性相关的方法

 1.4.1.3 获得类中构造器相关的方法

  1.4.1.4 获得类中方法相关的方法

1.4.2 获取Class对象

  1.  第一种,使用 Class.forName("类的全路径名"); (静态方法)(常用)                                  例:Class<?> c1 = Class.forName("reflectdemo.Student");

  2. 使用 .class 方法。                                                                                                              例:Class c2 = Student.class;

  3. 使用类对象的 getClass() 方法。                                                                                         例:Student student = new Student();Class<?> c3 = student.getClass();

1.5 总结

反射优点:

  1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。
  2.  增加程序的灵活性和扩展性,降低耦合性,提高自适应能力。
  3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。 

反射缺点:

  1. 调用大量方法,导致程序效率降低 。
  2. 会带来维护问题。
  3. 反射代码比相应的直接代码更复杂 。

1.6 代码实例

public static void reflectPrivateField() {
        try {
            Class<?> c1 = Class.forName("reflectdemo.Student");
            Field field = c1.getDeclaredField("name");
            field.setAccessible(true);//修改private修饰的成员,需要添加这条语句

            //获取Student对象
            Student student = (Student)c1.newInstance();

            field.set(student,"poll");

            System.out.println(student);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

2、枚举

2.1 定义

枚举的使用语法:用enum代替class关键字,定义一个枚举类。枚举类实际上就是一个类。

其中的RE、 BLACK、GREEN ,叫做枚举对象

能够将常量组织起来统一进行管理,不具备整形等值的概念,是枚举类型。

本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了Enum类。

2.1.1 简单使用

public enum Color {
    RED,PICK,BLACK,BLUE;//枚举对象

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

2.2 常用方法

因为任何的自定义枚举类都继承自Enum类,故继承了Enum类的方法:

其中 valueOf方法,只能转化成已有的枚举对象。

方法使用:

public enum Color {
    RED,PICK,BLACK,BLUE;//枚举对象
    public static void main(String[] args) {
        Color[] colors = Color.values();//将枚举对象转化为数组
        for (Color color : colors) {
            System.out.println(color+" "+color.ordinal());//获取索引
        }
        System.out.println("====");
        Color color = Color.valueOf("RED");//将字符串转化为枚举对象(只能转化成已有的枚举对象)
        System.out.println(color);

        System.out.println("===");
        System.out.println(RED.compareTo(PICK));//比较枚举对象的定义顺序(下标差)
    }    
}

2.3 构造方法

因为枚举本身就是一个类,所以也有普通类所具备的构造方法。

当我们没有写出任何构造方法时,Java会帮我们默认提供不带参数的构造方法,所以我们实例出的枚举对象不用传入参数。但是当我们写出带参构造时,我们就需要自主给枚举对象提供相应参数。

但是这里重点要说的是:枚举的构造方法默认是私有的。

我们发现,当private修饰构造方法时,private显示为灰色(上图),说明构造方法默认是私有的,当我们使用public修饰时,会编译报错:

2.4 枚举和反射(阿里面试:为什么枚举实现单例模式是安全的?)

我们上文讲到了反射可以拿到类中所有的属性和方法,包括private私有的,那么枚举的构造方法也是私有的,我们是否可以拿到呢?

答案是:反射不可以拿到枚举的构造方法。

 

 当我们通过反射(newInstance方法中)去获取枚举对象时,直接抛出了异常,也就是说,在反射中,枚举被过滤掉了,所以我们不能通过反射获取枚举类的实例!!!

总结:枚举是非常安全的,甚至不可以用反射获取枚举的实例。 

 2.5 总结

  1. 枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承与 java.lang.Enum
  2. 枚举的构造方法默认是私有的
  3. 枚举可以避免反射和序列化问题
  4. 枚举常量更简单安全
  5. 枚举不可继承,无法扩展

3、Lambda表达式

3.1 定义

Lambda表达式是JDK8引入的一种语法形式,主要用来简化代码,语法为:

3.2 函数式接口

Lambda表达式主要用来简化匿名内部类的书写,而且只能简化函数式接口的匿名内部类的书写。

函数式接口:

  • 有且仅有一个抽象方法的接口
  • 我们可以为函数式接口添加@FunctionalInterface 注解,当其不是函数式接口时,编译器会报错。

所以我们可以这样理解Lambda表达式:Lambda就是匿名内部类的简化,实际上是创建了一个匿名类的对象,实现了函数式接口,重写了接口的方法 。 

3.3 省略规则

  • 省略所实现接口的表示,省略方法名、返回值,只保留重写方法的参数列表和方法体

  • 参数类型可省略,若要省略则全部参数的类型都要省略

  • 若只有一个参数,那么参数的小括号可省略;若有两个参数,则小括号不可省略。

  • 参数和方法体间使用 -> 连接

  • 若方法体当中只有一句代码,那么花括号可以省略,分号可以省略

  • 如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字,去掉分号

代码演示:

public static void main(String[] args) {
        //原匿名内部类形式
        PriorityQueue<String> queue1 = new PriorityQueue<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        //Lambda表达式形式
        PriorityQueue<String> queue2 = new PriorityQueue<>((o1,o2) -> o2.compareTo(o1));
    }

3.4 变量捕获

变量捕获就是在匿名内部类中使用到了一个变量,那这个变量在使用前或者使用后都不能做出修改,否则会编译报错(这个变量就叫做被捕获的变量):

在匿名内部类中存在变量捕获,那么在Lambda表达式中也必然存在:

 

上述代码中变量aaaa就叫做:被捕获的变量 

所以我们得出结论:

  1. 这个变量要么是被final修饰为常量(常量不可修改)。
  2. 如果不是被final修饰的,我们要保证在使用之前和使用之后,没有修改。

 3.5 Lambda表达式在集合中的使用

3.5.1 forEach循环

forEach循环需要使用匿名内部类重写方法,我们可以使用Lambda表达式来简化代码。

3.5.1.1 Collection集合
public static void main1(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(23);
        list.add(29);
        list.add(13);

        //原形式
        list.forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.print(integer+" ");
            }
        });
        System.out.println();
        //Lambda形式
        list.forEach(integer -> System.out.print(integer+" "));
    }
3.5.1.2 Map集合
public static void main(String[] args) {
        HashMap<String,Integer> map = new HashMap<>();
        map.put("hello",10);
        map.put("world",13);
        map.put("abc",20);
        map.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println(s+" "+integer+" ");
            }
        });
        //Lambda形式
        map.forEach((key,value) -> System.out.println(key+" "+value+" "));

3.5.2 sort排序-forEach循环

3.5.2.1 List集合

List集合的sort方法,也可以使用匿名内部类重写方法来排序,我们可以使用Lambda形式:

public static void main2(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(23);
        list.add(29);
        list.add(13);
        //原匿名内部类排序形式
        /*list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });*/
        //Lambda形式 ->排序
        list.sort((o1, o2) -> o1.compareTo(o2));
        //Lambda形式 ->forEach循环
        list.forEach(integer -> System.out.print(integer+" "));
    }

END

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

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

相关文章

DeFi革命:揭秘去中心化金融的核心技术与实操指南

目录 DeFi&#xff08;去中心化金融&#xff09;综述 基本特点 第一&#xff0c;DeFi 是无许可的金融 第二&#xff0c;DeFi 是无门槛的金融 第三&#xff0c;DeFi 是无人驾驶的金融 典型商业模式 闪电贷 MakerDAO 面临的挑战 DeFi技术要点 椭圆曲线签名 EIP-712:…

IS-LM模型的公式与应用解析

IS-LM模型的公式与应用解析 IS-LM模型的核心作用 IS-LM模型是宏观经济学中的一个重要工具&#xff0c;用于分析财政政策和货币政策对经济的影响。IS曲线代表商品市场均衡&#xff0c;LM曲线代表货币市场均衡。两条曲线的交点表示商品市场和货币市场同时达到均衡时的利率和收入…

MySQL笔记3——高级数据查询语句DQL

多表联查 多表联查可以通过连接运算实现&#xff0c;即将多张表通过主外键关系关联在一起进行查询。下图提供了多表联查 时用到的数据库表之间的关系。 等值查询和非等值查询 非等值查询&#xff1a;SELECT * FROM 表1&#xff0c;表2 等值查询&#xff1a;SELECT * FROM 表…

DDR3布线时候的经验总结

摆放BGA下面的滤波电容的时候注意不要让两个电容的电源和地对着头放&#xff0c;手工焊接时候容易短路 阻抗层必须是实心铜皮覆盖&#xff1a; &#xff08;3&#xff09;阻抗线一定要有阻抗参考层&#xff0c;一般以相邻的接地或电源层做参考层&#xff08;如顶层阻抗线&…

人工智能技术的分析与探讨

《人工智能技术的分析与探讨》 摘要&#xff1a; 本文深入探讨了人工智能技术在多个领域的应用&#xff0c;包括智能感知、智能语音、智能问答、智能机器人、智能制造、智能医疗等。详细阐述了这些技术在当前的应用现状和主要场景&#xff0c;展示了一些典型的应用案例&#…

放大电路总结

补充: 只有直流移动时才有Rbe动态等效电阻 从RsUs看进去,实际上不管接了什么东西都能够看成是一个Ri(输入电阻) Ri Ui/Ii Rb//Rbe Ui/Us Ri/(RiRs) Aus (Uo/Ui)*(Ui/Us) Au *Ri/(RiRs) 当前面是一个电压源的信号 我们就需要输入电阻更大 Ro--->输出电阻--->将…

学习C语言第十四天(指针练习)

1.第一题C 2.第二题C 3.第三题 00345 short类型解引用一次访问两个字节 4.第四题 6&#xff0c;12 5.第五题C 6.第六题 下面代码结果是0x11223300 7.第七题 int main() {int a 0;int n 0;scanf("%d %d",&a,&n);int i 0;int k 0;int sum 0;for (i 0;…

创维汽车滁州永通体验中心开业仪式暨超充车型区域上市会圆满成功

2024年7月20日&#xff0c;创维汽车滁州永通体验中心盛大开业&#xff0c;当日&#xff0c;创维汽车市场部经理周世鹏、安徽大区总监王大明等领导参加本次开业盛典&#xff0c;共同见证创维汽车滁州永通体验中心成功落地。 2021年&#xff0c;新能源乘用车高速发展&#xff0c;…

安装CUDA Cudnn Pytorch(GPU版本)步骤

一.先看自己的电脑NVIDIA 支持CUDA版本是多少&#xff1f; 1.打开NVIDIA控制面板 2.点击帮助---系统信息--组件 我的支持CUDA11.6 二.再看支持Pytorch的CUDA版本 三.打开CUDA官网 下载CUDA 11.6 下载好后&#xff0c;安装 选择 自定义 然后安装位置 &#xff08;先去F盘…

MySQL可重复读的隔离机制下是否彻底解决了幻读?

答案&#xff1a;没有彻底解决。 一、什么是幻读&#xff1f; 当同一个查询在不同时间产生不同的结果集时&#xff0c;事务中就会出现幻读问题。 幻读关注的是记录数量的不同。 不可重复读关注的是记录内容的不同。 二、快照读和当前读 InnoDB引擎的默认隔离级别是可重复读&…

vue3 命令运行窗口暴露网络地址,以及修改端口号

一般情况下这里的地址是隐藏的 这里加上 --host 可以暴露网络地址&#xff0c;再加上--port --8080 就可以将端口号修改为8080&#xff08;修改后边的数字就可以修改为你想要的端口号&#xff09;

pytorch-训练自定义数据集实战

目录 1. 步骤2. 加载数据2.1 继承Dataset2.1.1 生成name2label2.1.2 生成image path, label的文件2.1.3 __len__2.1.3 __getitem__2.1.4 数据切分为train、val、test 3. 建立模型4. 训练和测试4. 完整代码 1. 步骤 加载数据创建模型训练和测试迁移学习 2. 加载数据 这里以宝…

打造创新项目:从理念到市场的成功之路

打造创新项目&#xff1a;从理念到市场的成功之路 前言为何创新&#xff1f;如何创新&#xff1f;创新的意义 一、深入市场&#xff0c;洞察行业脉搏二、精准定位&#xff0c;锁定目标市场三、全面评估&#xff0c;确保项目可行性四、创新引领&#xff0c;打造独特卖点五、开放…

二叉树_堆(下卷)

前言 接前面两篇的内容&#xff0c;接着往下讲二叉树_堆相关的内容。 正文 那么&#xff0c;回到冒泡排序与堆排序的比较。 我们知道冒泡排序的时间复杂度为 O ( N 2 ) O(N^2) O(N2)&#xff0c;这个效率是不太好的。 那么&#xff0c;我们的堆排序的时间复杂度如何呢&…

Linux:进程概述(什么是进程、进程控制块PCB、并发与并行、进程的状态、进程的相关命令)

进程概述 (1)What&#xff08;什么是进程&#xff09; 程序&#xff1a;磁盘上的可执行文件&#xff0c;它占用磁盘、是一个静态概念 进程&#xff1a;程序执行之后的状态&#xff0c;占用CPU和内存&#xff0c;是一个动态概念&#xff1b;每一个进程都有一个对应的进程控制块…

云计算复习--分布式存储系统

分布式存储 分布式存储系统是一种将数据分散在多个独立节点上&#xff0c;并通过网络进行数据传输和访问的存储系统 分布式存储的特点&#xff1a;可扩展性、高可用性、容错性、高性能等。分布式存储系统能够水平扩展存储容量和性能&#xff0c;提供持续可用的数据存储服务&am…

【在开发小程序的时候如何排查问题】

在开发小程序的时候如何排查问题 在最近开发小程序的时候&#xff0c;经常出现本地在浏览器中调试没有问题&#xff0c;但是一发布到预发环境就出现各种个样的问题 手机兼用性问题 有时候会出现苹果&#x1f34e;手机键盘弹出&#xff0c;导致ui界面高度出现异常边界问题&#…

for循环打印1~10之间数字

对于for循环之前了解不够的同学可以看之前的我写的介绍 我们这里直接上代码 #include<stdio.h> int main() {int i 0;for (i 1; i < 11; i){printf("%d\n", i);}return 0; }

0724_驱动1 字符设备驱动内部实现

一、字符设备驱动内部实现工作原理 二、分布实现字符设备驱动API接口 分配对象&#xff1a; #include <linux/cdev.h> struct cdev *cdev_alloc(void) 函数功能&#xff1a;分配对象struct cdev *结构体指针 参数&#xff1a;无 返回值&#xff1a;成功返回struct cdev *…

人工智能类——计算机科学与技术

计算机科学与技术是一个非常大的门类。目前计算机科学与技术类招生的专业主要有计算机科学与技术、软件工程、网络工程、信息安全、物联网工程等&#xff0c;后面的几个专业是计算机科学与技术的重要分支&#xff0c;而这个门类的其他分支并没有单列出来一个本科专业&#xff0…