首页 > 编程语言 >数据结构(Java):反射&枚举&Lambda表达式

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

时间:2024-07-28 11:56:40浏览次数:15  
标签:反射 Java System 枚举 Lambda Class out

目录

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

标签:反射,Java,System,枚举,Lambda,Class,out
From: https://blog.csdn.net/2401_83595513/article/details/140726230

相关文章

  • 探索 IPython 中的 %%javascript 魔法命令:运行 JavaScript 代码的秘籍
    引言IPython是一个强大的交互式计算环境,它不仅支持Python语言,还通过各种魔法命令扩展了其功能。其中,%%javascript魔法命令是IPython扩展中一个非常有趣的特性,它允许用户在IPython环境中直接运行JavaScript代码。这对于需要在数据科学和科学计算中使用JavaScript......
  • Redis Java客户端(带示例代码)
    目录概述Jedis--快速入门Jedis简介创建项目和测试1.引入依赖2.建立连接3.测试4.释放资源Jedis连接池JedisPool简介创建连接池使用连接池概述在Redis官网中提供了各种语言的客户端网站:ConnectwithRedisclients标记为❤的就是推荐使用的java客......
  • 利用Java调用银行卡二要素接口
    一、什么是银行卡二要素?银行卡二要素验证接口是一种API接口,主要用于验证用户提供的银行卡号与姓名这两个要素是否一致。二、银行卡二要素作用及场景有哪些?其作用是通过核验用户的身份信息,判断是否为目标用户本人操作,常用于安全级别要求一般的使用场景,具体应用场景包括:1.......
  • 利用Java免费调用运营商三要素接口
    一、什么是运营商三要素?运营商三要素接口一般用于核验姓名、身份证号、手机号是否一致。它是电信运营商基于留存的实时数据,设计成API接口的形式,为有相关运营商查询核验需求的用户提供接入服务。二、以下是运营商三要素接口常见的使用场景:1.金融服务:在开户、贷款、申请信用......
  • 基于Java+Vue的采购管理系统:实现采购数字化升级(源代码)
      前言:采购管理系统是一个综合性的管理平台,旨在提高采购过程的效率、透明度,并优化供应商管理。以下是对各个模块的详细解释:一、供应商准入供应商注册:供应商通过在线平台进行注册,填写基本信息和资质文件。资质审核:系统对供应商提交的资质文件进行自动或人工审核,确保供应......
  • Java 自定义注解
    一、Java 自定义注解的用途、 1、可以记录在特殊方法进行日志记录     2、可以进行 特殊鉴权 如@ValidateRole(“admin") 只有当前用户拥有指定角色时才放行 否则抛自定义异常 无权限    3、可以用于参数 如Controller 方法中的参数进行 参数......
  • Java计算机毕业设计旅游服务管理系统(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着旅游业的蓬勃发展,旅游服务管理的复杂性与日俱增。传统的手工管理方式已难以满足现代旅游业的高效、精准服务需求。特别是在用户体验、旅游团管理......
  • Java计算机毕业设计驾校学员管理系统(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着汽车保有量的持续增长,驾驶技能已成为现代社会不可或缺的基本技能之一。驾校作为培养驾驶员的重要机构,其学员管理效率与服务质量直接影响到学员的......
  • Java计算机毕业设计美食商城(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着互联网的飞速发展和人们生活水平的日益提高,美食不再仅仅是满足口腹之欲的简单需求,它已经成为了一种文化、一种生活方式,甚至是一种社交媒介。在这......
  • Java计算机毕业设计结合疫情情况的婚恋系统(开题报告+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景近年来,全球疫情的持续影响不仅改变了人们的生活方式,也深刻影响了人们的社交与情感需求。在隔离与社交距离成为常态的背景下,传统线下相亲、约会活动受......