当前位置: 首页 > backend >正文

反射,枚举,lambda表达式

目录

  • 反射
  • 枚举的使用
  • Lambda表达式
      • 函数式接口
      • 语法
      • Lambda表达式语法精简
    • 变量捕获
    • Lambda在集合List中的使用


反射

作用:在Java代码中,让一个对象认识到自己
比如一个类的名字,里面的方法,属性等
让程序运行的过程,某个对象也能获取到上述信息
Java提供了一组 API,通过这些 API 拿到指定对象的上述信息

注:API全称Application Programming Interface,它是一组方法和类,提供给别人使用的,例如Scanner,Queue,List
如:
在这里插入图片描述
像这样得到String的全部信息

在这里插入图片描述
获取用户输入的想要的类型(动态的过程)
newInstance:获取实例
forName:获取对象

反射的作用:
把序列化的字符串还原成对象(反序列化)
序列化:把一个对象转成一个字符串

获取到类的某个属性(Field):
在这里插入图片描述
获取到某个方法(Method):
在这里插入图片描述

如果print1有两个方法(重写),具体调用哪个方法也是可以明确使用的
例如有一个print(String x)
如果调用上面的方法,可以用
Method pm=studentClass.getDeclaredMethod(“print”,String.class);
通过后续的参数,区分出当前要获取的print是哪个版本,后续参数就表示‘获取方法的参数列表’
完整访问:

class Student{private int id=1;private String name;public void print(){System.out.println("id:"+id+"name:"+name);}public void print(String p){System.out.println(p+" id:"+id+" name:"+name);}
}
public class Test2 {public void test1() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {Class studentClass=Class.forName("Student");Field idField=studentClass.getDeclaredField("id");//创建一个对象Student student=new Student();//由于student的id是私有的,将它取出,相当于“开锁”idField.setAccessible(true);//设置里面的值idField.setInt(student,100);int id=idField.getInt(student);//获取值System.out.println(id);}public void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {//通过反射调用 Student 方法Class studentClass=Student.class;//拿到方法对象Method pm=studentClass.getDeclaredMethod("print",String.class);Student student=new Student();//随便创建一个对象pm.setAccessible(true);pm.invoke(student,"hello,");//调用方法}public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {Test2 test=new Test2();test.test2();//结果:hello, id:1 name:null}
}

通过反射,能随意访问任意对象的任意属性
反射的缺点:大大降低了效率,绕过了源代码,提高了维护成本,不到万不得已不要使用

枚举的使用

在这里插入图片描述

public enum Gender {//每个枚举项通常用大写字母来表示,本质上是一组常量//这几个常量类型都是Gender,但值不同//常量使用都好分割MALE,FEMALE,OTHER
}

在main方法中使用:
在这里插入图片描述

此外,枚举中还能指定属性和方法(枚举和类很相似)

枚举和类的区别:
类可以随意在外面创建实例,但枚举不行,
枚举项的创建必须在 枚举的内部进行(构造方法必须是私有的)
在这里插入图片描述

Color c=Color.RED;System.out.println(c.getName());//结果:红色

枚举不可继承,无法扩展

问:能否通过反射,拿到私有的构造方法,然后在枚举外面创建出新的枚举项?
答:不能,Java的反射 API 中,针对枚举值特殊情况做了特殊处理

Lambda表达式

函数式接口

由于Java没有其他编程语言拥有的匿名函数(没有名字的函数,用完一次就扔了,通常作为“回调函数”用,类似于Comparetor,Comparable)
Java引入“函数式接口” 来引申出匿名函数=>这就是Lambda 表达式
如果一个接口里面只有一个抽象方法,就可以称为函数式接口

语法

Lambda表达式语法精简

  1. 参数类型可以省略,如果需要省略每个参数的类型都要省略
  2. 参数的⼩括号⾥⾯只有⼀个参数,那么⼩括号可以省略
  3. 如果⽅法体当中只有⼀句代码,那么⼤括号可以省略
  4. 如果⽅法体中只有⼀条语句,且是return语句,那么⼤括号可以省略,且去掉return关键字

1.比如优先级队列调用Comparator
正常用匿名内部类写法如下:

public class Test5 {class Student{public String name;public int id;}public static void main(String[] args) {PriorityQueue<Student> priorityQueue=new PriorityQueue<>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.id-o2.id;}});}

而使用Lambda表达式更简单:

public static void main(String[] args) {PriorityQueue<Student> priorityQueue=new PriorityQueue<>((o1, o2) -> o1.id-o2.id);}

(o1,o2)里面表示形参列表,形参的参数类型是可以省略的
-> 是Lambda的关键标志,一看到这个箭头,就知道是Lambda
o1.id-o2.id 是lambda的函数体(如果 lambda 里只有一句return代码,{ } 就可以省略,return也能省略)

2.例如使用函数式接口:

interface MyInterface{//函数式接口void print(String s);
}public class Test6 {//用lambda表达式MyInterface myInterface=(s)-> System.out.println(s);//不用lambda表达式MyInterface myInterface1=new MyInterface() {@Overridepublic void print(String s) {System.out.println(s);}};
}

可见lambda表达式能大量减少代码量

3.把 lambda 表达式的内容作为另一个方法的实参(前提是 该形参的类型必须是函数式接口):

interface MyComparator{int compare(String s1,String s2);
}
class MyPriorityQueue{public MyPriorityQueue(MyComparator comparator){//函数式接口作为形参}
}
public class Test7 {public static void main(String[] args) {MyPriorityQueue queue=new MyPriorityQueue((s1,s2)->s1.compareTo(s2));}
}

第四个例子用的比较少,可以了解

lambda表达式最主要的功能就是省略,写起来简便

变量捕获

在 Lambda 表达式里捕获的变量必须是 final 或者是事实上的 final(即一旦赋值就不会再改变)

lambda 表达式能够捕获外部的变量,在内部进行使用
在这里插入图片描述

lambda的变量捕获,能把创建后销毁掉的变量再拿出来(这是很可怕的一件事)
相当于上头断了线,下面还在执行
在这里插入图片描述

Lambda 能够使用捕获的变量的原因:在定义 lambda 的时候就把捕获的变量在 lambda 内部拷贝(地址不同)了一份
所以我们不能让捕获到的num(变量) 之后还能继续修改否则拷贝的和外面的num会出现歧义
因此,规定捕获到的变量必须是final的或没有进行修改的

Lambda在集合List中的使用

public class Test8 {public static void main(String[] args) {List<Integer> list=new ArrayList<>();list.add(1);list.add(2);list.add(3);for (int i=0;i<list.size();i++){//正常写法System.out.print(list.get(i)*2+" ");}//用lambda表达式写list.forEach(i -> System.out.print(i*2+" "));}
}
http://www.xdnf.cn/news/1612.html

相关文章:

  • 网页版 deepseek 对话问答内容导出为 PDF 文件和 Word 文件的浏览器插件下载安装和使用说明
  • 【axios取消请求】如何在token过期后取消未响应的请求
  • 针对密码学的 EM 侧信道攻击
  • git 操作
  • Golang编程拒绝类型不安全
  • 嵌入式人工智能应用-第三章 opencv操作8 图像特征之 Haar 特征
  • springboot整合redis实现缓存
  • 协作开发攻略:Git全面使用指南 — 第二部分 高级技巧与最佳实践
  • 无标注文本的行业划分(行业分类)算法 —— 无监督或自监督学习
  • 【TensorFlow深度学习框架】从数学原理到工业级应用
  • 硬件工程师面试常见问题(7)
  • 【GIT】github中的仓库如何删除?
  • Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite验收用户名和密码
  • 从指标定义到可视化:基于衡石指标平台的全链路数据治理实战
  • 4.1.1 类的序列化与反序列化(XmlSerializer)
  • 一文走进GpuGeek | 模型调用
  • Python 面向对象练习
  • 探秘 FFmpeg 版本发展时间简史
  • SpringMVC处理请求映射路径和接收参数
  • 配置RSUniVLM环境(自用)
  • [特殊字符] 分布式定时任务调度实战:XXL-JOB工作原理与路由策略详解
  • IDEA启动报错Failed to create JVM. JVM path的解决办法
  • (51单片机)LCD展示动画(延时函数)(LLCD1602教程)
  • 2025最新系统 Linux 教程(六)
  • Puter部署指南:基于Docker的多功能个人云平台掌控自己的数据
  • uniapp-商城-34-shop 购物车 选好了 进行订单确认
  • java—12 kafka
  • Kubernetes(K8S)入门阶段详细指南
  • 微信小程序根据图片生成背景颜色有效果图
  • 并发设计模式实战系列(6):读写锁