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

Java 高级特性” 体系(反射 + 枚举 + Lambda)

1.反射

1.1 定义

Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;不用new,不用知道类名,也能操作类。

1.2 用途

  • 框架底层核心(Spring、MyBatis 全靠反射)
  • 动态加载类、动态调用方法
  • 突破私有访问限制

1.3 反射基本信息

Java程序中许多对象在运行时会出现两种类型:运行时类型 和 编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。

1.4 反射相关的类

类名用途链接文档
Class类类的实体,在运行的Java应用程序中表示类和接口Class | API reference | Android Developers
Field类类的成员变量/类的属性Field | API reference | Android Developers
Method类类的方法Method | API reference | Android Developers
Constructor类类的构造方法Constructor | API reference | Android Developers

1.5 反射示例

1.51获得Class对象的三种方式

第一种,使用 Class.forName(“类的全路径名”); 静态方法。前提:已明确类的全路径名。

第二种,使用 .class 方法。说明:仅适合在编译前就已经明确要操作的 Class

第三种,使用类对象的 getClass() 方法

package test; public class demo5 { static class Student{ } public static void main(String[] args) { //1.通过getClass获取Class对象 Student s1 = new Student(); Class c1 = s1.getClass(); //2.直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高 //这说明任何一个类都有一个隐含的静态成员变量 class Class c2 = Student.class; //3、通过 Class 对象的 forName() 静态方法来获取,用的最多, //但可能抛出 ClassNotFoundException 异常 Class c3 = null; try { //注意这里是类的全路径,如果有包需要加包的路径 //c3 = Class.forName("test.demo5.Student"); ❌ c3 = Class.forName("test.demo5$Student");✅ } catch (ClassNotFoundException e) { e.printStackTrace(); } //一个类在 JVM 中只会有一个 Class 实例,即我们对上面获取的 //c1,c2,c3进行 equals 比较,发现都是true System.out.println(c1.equals(c2)); System.out.println(c1.equals(c3)); System.out.println(c2.equals(c3)); } }
获取方式语法特点适用场景
对象.getClass()s1.getClass()必须先创建对象,运行时获取已经有对象,需要获取类信息
类名.classStudent.class不需要创建对象,编译期获取,性能最高、最安全编译期就知道类名,静态获取
Class.forName()Class.forName("全类名")动态加载,只需要类名字符串,可配置框架动态加载类、配置文件指定类名

🎯 为什么test.demo5.Student是错的,test.demo5$Student是对的?

这是静态内部类的全限定名规则:

  • .符号:只代表「包层级」

    • test.demo5.Student会被 JVM 理解为:test包 →demo5包 →Student
    • 但你的demo5不是包,是外部类Studentdemo5里的静态内部类,所以 JVM 根本找不到这个类,直接抛异常ClassNotFoundException
  • $符号:代表「内部类」

    • Java 规定:内部类(包括静态内部类)的全限定名,必须用$分隔外部类和内部类
    • 编译后,静态内部类会生成独立的字节码文件:demo5$Student.classforName就是根据这个文件名加载类的
    • 所以正确写法是test.demo5$Student,表示test包下,demo5类的内部类Student.

1.6反射优点和缺点

优点:

  1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
  2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
  3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
    缺点:
    1.使用反射会有效率问题。会导致程序效率降低.
    2.反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

2 枚举

2.1 定义

枚举是一组固定不变的常量,用来代替大量public static final常量,代码更简洁、更安全。本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了这个类。

2.2 使用

2.2.1.sitch语句

package test; public class demo6 { public enum TestEnum { RED,BLACK,GREEN,WHITE,hhh; public static void main(String[] args) { TestEnum testEnum2 = TestEnum.hhh; switch (testEnum2) { case RED: System.out.println("red"); break; case BLACK: System.out.println("black"); break; case WHITE: System.out.println("WHITE"); break; case GREEN: System.out.println("black"); break; default: System.out.println("不是颜色"); } } } }

2.2.2、常用方法

Enum 类的常用方法

方法名称描述遍历方法
values()以数组形式返回枚举类型的所有成员遍历所有枚举
ordinal()获取枚举成员的索引位置获取枚举序号
valueOf()将普通字符串转换为枚举实例字符串转枚举
compareTo()比较两个枚举成员在定义时的顺序枚举比较
package test; public class demo7{ public enum TestEnum { RED, BLACK, GREEN, WHITE; public static void main(String[] args) { TestEnum[] testEnum2 = TestEnum.values(); for (int i = 0; i < testEnum2.length; i++) { System.out.println(testEnum2[i] + " " + testEnum2[i].ordinal()); } System.out.println("========================="); System.out.println(TestEnum.valueOf("GREEN")); System.out.println("========================="); TestEnum testEnum = TestEnum.BLACK; TestEnum testEnum21 = TestEnum.RED; System.out.println(testEnum.compareTo(testEnum21)); System.out.println(BLACK.compareTo(RED)); System.out.println(RED.compareTo(BLACK)); } } }

2.3 枚举优点缺点

优点:

  1. 枚举常量更简单安全 。
  2. 枚举具有内置方法 ,代码更优雅
    缺点:
    1.不可继承,无法扩展

💡为什么枚举实现单例模式是安全的?与他们三个有关系吗?

枚举天生就是单例,而且是 Java 中最安全、最优雅的单例实现,没有之一

  • 枚举实例在 JVM 中天然是单例且全局唯一

    枚举里的每个常量,本质都是public static final的,在类加载阶段就初始化,由 JVM 保证只会存在一个实例。

  • 构造方法天然私有,外部无法通过 new 创建对象

    枚举的构造器默认就是 private,而且编译器不允许我们把它改成 public,从根源上杜绝了手动实例化。

  • 可以防止反射攻击

    普通单例可以通过反射暴力调用私有构造方法,从而破坏单例;

    但 JVM 对枚举做了特殊处理,反射无法通过 new Instance 创建枚举对象,会直接抛出异常,因此单例不会被破坏。

  • 可以防止序列化破坏单例

    普通 Java 对象序列化再反序列化时,会创建一个新对象;

    而枚举序列化时只传输名字,反序列化时通过valueOf()找原有常量,不会产生新实例,依然保持单例。

  • 天然线程安全

    因为是在类加载阶段初始化,不存在多线程并发问题,不需要加锁,也不需要做双重校验。

  • 枚举直接相关:它本身就是用枚举特性实现的。

  • 反射强相关:普通单例会被反射破坏,枚举不会。

  • Lambda 基本无关,Lambda 只是函数式写法,不影响单例安全。

3.Lambda表达式

3.1 是什么?

简化的匿名内部类写法,专门用于函数式接口(只有一个抽象方法的接口)。

(参数) -> { 代码体 }
//无返回值无参数 @FunctionalInterface interface NoParameterNoReturn { void test(); } //无返回值一个参数 @FunctionalInterface interface OneParameterNoReturn { void test(int a); } //无返回值多个参数 @FunctionalInterface interface MoreParameterNoReturn { void test(int a,int b); } //有返回值无参数 @FunctionalInterface interface NoParameterReturn { int test(); } //有返回值一个参数 @FunctionalInterface interface OneParameterReturn { int test(int a); } //有返回值多参数 @FunctionalInterface interface MoreParameterReturn { int test(int a,int b); }

3.2 Lambda表达式的基本使用

package test; // 1. 无参数无返回值 函数式接口 @FunctionalInterface interface NoParameterNoReturn { void test(); } // 2. 一个参数无返回值 函数式接口 @FunctionalInterface interface OneParameterNoReturn { void test(int a); } // 3. 多个参数无返回值 函数式接口 @FunctionalInterface interface MoreParameterNoReturn { void test(int a, int b); } // 4. 无参数有返回值 函数式接口 @FunctionalInterface interface NoParameterReturn { int test(); } // 5. 一个参数有返回值 函数式接口 @FunctionalInterface interface OneParameterReturn { int test(int a); } // 6. 多个参数有返回值 函数式接口 @FunctionalInterface interface MoreParameterReturn { int test(int a, int b); } public class demo8 { public static void main(String[] args) { // 1. 无参无返回 NoParameterNoReturn noParameterNoReturn = () -> { System.out.println("无参数无返回值"); }; noParameterNoReturn.test(); // 2. 单参无返回 OneParameterNoReturn oneParameterNoReturn = (int a) -> { System.out.println("一个参数无返回值:" + a); }; oneParameterNoReturn.test(10); // 3. 多参无返回 MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> { System.out.println("多个参数无返回值:" + a + " " + b); }; moreParameterNoReturn.test(20, 30); // 4. 无参有返回 NoParameterReturn noParameterReturn = () -> { System.out.println("有返回值无参数!"); return 40; }; int ret = noParameterReturn.test(); System.out.println(ret); // 5. 单参有返回 OneParameterReturn oneParameterReturn = (int a) -> { System.out.println("有返回值有一个参数!"); return a; }; ret = oneParameterReturn.test(50); System.out.println(ret); // 6. 多参有返回 MoreParameterReturn moreParameterReturn = (int a, int b) -> { System.out.println("有返回值多个参数!"); return a + b; }; ret = moreParameterReturn.test(60, 70); System.out.println(ret); } }

3.3. 语法精简

public static void main(String[] args) { MoreParameterNoReturn moreParameterNoReturn = ( a, b)->{ System.out.println("无返回值多个参数,省略参数类型:"+a+" "+b); }; moreParameterNoReturn.test(20,30); OneParameterNoReturn oneParameterNoReturn = a ->{ System.out.println("无参数一个返回值,小括号可以胜率:"+ a); }; oneParameterNoReturn.test(10); NoParameterNoReturn noParameterNoReturn = ()->System.out.println("无参数无返回值,方法体中只有一行代码"); noParameterNoReturn.test(); //方法体中只有一条语句,且是return语句 NoParameterReturn noParameterReturn = ()-> 40; int ret = noParameterReturn.test(); System.out.println(ret); }

3.4 Lambda在集合当中的使用

接口名称新增方法核心作用
CollectionforEach()遍历集合,支持 Lambda 表达式
removeIf(Predicate<? super E> filter)根据条件批量删除元素
stream()获取集合的顺序流(Stream),用于流式操作
parallelStream()获取集合的并行流,提升大数据量处理效率
spliterator()获取可分割迭代器,用于并行遍历
ListreplaceAll(UnaryOperator<E> operator)对集合中所有元素执行统一操作,批量替换
sort(Comparator<? super E> c)直接在 List 上排序,无需额外创建数组
Map<K,V>getOrDefault(Object key, V defaultValue)键不存在时返回默认值,避免空指针
forEach(BiConsumer<? super K,? super V> action)遍历 Map,支持 Lambda 处理键值对
replaceAll(BiFunction<? super K,? super V,? extends V> function)批量更新 Map 中所有值
putIfAbsent(K key, V value)键不存在时才插入,存在则不覆盖
remove(Object key, Object value)仅当键值对完全匹配时才删除
replace(K key, V value)/replace(K key, V oldValue, V newValue)替换指定键的值,支持新旧值校验
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)键不存在时,计算并插入新值
computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)键存在时,计算并更新值
compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)无论键是否存在,直接计算并更新值
merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)合并新旧值,灵活处理键值对

3.5 代码展示

Collection中的 forEach() 方法演示

package test; import java.util.ArrayList; import java.util.function.Consumer; public class demo10 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("西安"); list.add("hello"); list.add("中国"); list.forEach(new Consumer<String>(){ @Override public void accept(String str){ //简单遍历集合中的元素。 System.out.print(str+" "); } }); } }

修改为lambda表达式:

package test; import java.util.ArrayList; import java.util.function.Consumer; public class demo10 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("西安"); list.add("hello"); list.add("中国"); //表示调用一个,不带有参数的方法,其执行花括号内的语句,为原来的函数体内容。 list.forEach(s -> { System.out.print(s); }); } }

List中的 sort()方法的演示

package test; import java.util.ArrayList; import java.util.Comparator; public class demo12 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("西安"); list.add("hello"); list.add("中国"); list.sort(new Comparator<String>() { @Override public int compare(String str1, String str2){ //注意这里比较长度 return str1.length()-str2.length(); } }); System.out.println(list); } }

修改为lambda表达式:

package test; import java.util.ArrayList; import java.util.Comparator; public class demo12 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Hello"); list.add("西安"); list.add("hello"); list.add("中国"); //调用带有2个参数的方法,且返回长度的差值 list.sort((str1,str2)-> str1.length()-str2.length()); System.out.println(list); } }

Map 中的 forEach() 方法演示

package test; import java.util.HashMap; import java.util.function.BiConsumer; public class demo13 { public static void main(String[] args) { HashMap<Integer, String> map = new HashMap<>(); map.put(1, "hello"); map.put(2, "西安"); map.put(3, "hello"); map.put(4, "中国"); map.forEach(new BiConsumer<Integer, String>(){ @Override public void accept(Integer k, String v){ System.out.println(k + "=" + v); } }); } }

修改为lambda表达式:

package test; import java.util.HashMap; import java.util.function.BiConsumer; public class demo13 { public static void main(String[] args) { HashMap<Integer, String> map = new HashMap<>(); map.put(1, "hello"); map.put(2, "西安"); map.put(3, "hello"); map.put(4, "中国"); map.forEach((k,v)-> System.out.println(k + "=" + v)); } }

3.6Lambda 优缺点

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。
优点:

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作
    缺点:
    1.代码可读性变差
    2.在非并行计算中,很多计算未必有传统的 for 性能要高
    3.不容易进行调试
http://www.jsqmd.com/news/637738/

相关文章:

  • Halcon实战:光源不均场景下的平场矫正优化策略
  • # Claude API 国内直连:技术原理与稳定接入方案
  • 2026年评价高的沈阳城市夜景亮化灯/沈阳楼体亮化灯/沈阳双头壁灯/沈阳地埋灯横向对比厂家推荐 - 品牌宣传支持者
  • Couldn‘t start dlv dap:Error:spawn UNKNOWN
  • 旋架式加速度过载模拟实验台结构设计与分析(论文+CAD+SolidWorks+开题报告+任务书+外文翻译……)
  • 配置文件编辑工具:速度与精度
  • 工业一体机存储配置标准:内存硬盘支持规格与扩展方案
  • 收藏!小白程序员也能快速入门大模型,直达高薪职业赛道!
  • C++代码静态检查脚本工具(指针判空越界访问除0风险)
  • TurboDiffusion让AI视频生成快100倍:零基础WebUI部署与实战演示
  • 支承套零件加工工艺编程及夹具设计(论文 CAD图纸 开题报告 任务书 加工程序)
  • 2026年质量好的沈阳道路路灯/沈阳洗墙灯/沈阳古建筑亮化灯/沈阳地埋灯优质公司推荐 - 行业平台推荐
  • Win10照片查看器失效?三步教你快速恢复
  • 以太坊 Q1 进入全面「重置」模式,一文详解其生态表现及发展重点
  • 大模型学习指南:收藏这份资料,小白程序员轻松掌握RAG,开启AI新技能!
  • 从混乱到清晰:如何用DRV8701E数据手册搞定双H桥电机驱动选型与外围电路设计
  • Qwen1.5-0.5B-Chat vs TinyLlama对比:轻量模型精度评测
  • ROS小车换雷达后建图重影?别急着调TF,先检查这个关键参数(附完整排查清单)
  • Twinkle Tray:Windows显示器亮度控制的终极完整指南
  • 普通老百姓60岁后如何保持身体硬朗?这5个习惯让你活出年轻态
  • 【Neural Whole-Body Control: HOVER ExBody2】4.4 Teacher-Student蒸馏与4.5 ExBody2 Specialist微调
  • 【Obsidian 】技术解析:本地优先知识管理工具的架构设计与核心机制深度剖析
  • STM32H723 + DP83848 + LWIP + RT-Thread Nano + STM32CubeMX 实战:内存规划、MPU配置与PHY驱动移植详解
  • Vivado 2018.3环境下的ZYNQ以太网开发避坑指南:GMII转RGMII核配置与LWIP Socket API调优
  • AI 驱动与 Wi-Fi 7 双剑合璧,全屋智能家居迎来“认知革命”
  • 蛋白互作研究核心技术:酵母文库与双杂交应用
  • **发散创新:基于以太坊Layer 2的Rollup扩容方案实战与性能优化**在区块链生态快速发展的今天,**可扩展性问题**已成
  • 每天睡前问三个问题,比检查作业更有效
  • 零基础掌握AI动作迁移:ComfyUI-MimicMotionWrapper完整指南
  • 智能网联汽车T-BOX硬件架构揭秘:STM32与SD NAND Flash的协同设计