1. 反射
1. 反射相关的类

2. Class类(反射机制的起源 )
1. Java程序运行的生命周期
-  
编译阶段
-  
Java源代码(.java文件)经过javac编译器编译
 -  
生成与平台无关的字节码文件(.class文件)
 -  
字节码文件包含类的结构信息和方法指令
 
 -  
 -  
类加载阶段
-  
JVM通过类加载器(ClassLoader)读取.class文件
 -  
将字节码数据转换为JVM内部的数据结构
 -  
创建对应的java.lang.Class对象
 
 -  
 -  
Class对象的作用
-  
每个加载的类在JVM中都有唯一的Class对象
 -  
Class对象包含类的完整元数据:
-  
类名、修饰符、包信息
 -  
字段(属性)信息
 -  
方法信息
 -  
构造器信息
 -  
注解信息
 
 -  
 
 -  
 -  
反射机制
-  
通过Class对象可以获取类的运行时信息
 -  
动态操作类的能力包括:
-  
创建类的实例
 -  
调用方法和访问字段
 -  
修改访问权限
 -  
动态代理
 
 -  
 
 -  
 
2. 获得Class对象的三种⽅式
package reflection;public class Student {//私有属性private String name = "zhangshan";//公有属性public int age = 18;//不带参数的共有构造方法public Student(){System.out.println("student()");}//带一个参数的公有构造方法public Student(String name){this.name = name;System.out.println("Student(name)");}//带一个参数的私有构造方法private Student(int age){this.age = age;System.out.println("Student(age)");}//带两个参数的私有构造方法private Student(String name,int age){this.name = name;this.age = age;System.out.println("Student(name,age)");}//公有方法public void sleep(){System.out.println("I am sleepy");}//私有方法private void eat(String food){System.out.println("I love delicious food");}private void run(){System.out.println("Run fast");}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}public static void main(String[] args) {Student student = new Student();System.out.println(student);}
} 
//获得Class对象的三种⽅式
class Main {public static void main(String[] args) {//1. 通过Class.forName获取class对象Class<?> c1 = null;try{c1 = Class.forName("reflection.Student");}catch(ClassNotFoundException e){e.printStackTrace();}//2.直接通过 类名.class 的⽅式得到,该⽅法最为安全可靠,程序性能更⾼//这说明任何⼀个类都有⼀个隐含的静态成员变量 classClass<?> c2 = Student.class;//3. 通过getClass获取Class对象Student s3 = new Student();//创建对象Class<?> c3 = s3.getClass();//⼀个类在 JVM 中只会有⼀个 Class 实例,即我们对上⾯获取的//c1,c2,c3进⾏ equals ⽐较,发现都是trueSystem.out.println(c1.equals(c2));System.out.println(c1.equals(c3));System.out.println(c2.equals(c3));}
} 
3. Class类中的相关⽅法
1. 获取类信息
| 方法 | 返回值 | 用途 | 示例 | 
|---|---|---|---|
Class.forName("全限定类名") | Class<?> | 动态加载类 | Class.forName("java.lang.String") | 
对象.getClass() | Class<?> | 获取对象的 Class 对象 | "hello".getClass() | 
类名.class | Class<?> | 直接获取类的 Class 对象 | String.class | 
clazz.getName() | String | 获取全限定类名(如 "java.lang.String") | String.class.getName() | 
clazz.getSimpleName() | String | 获取简单类名(如 "String") | String.class.getSimpleName() | 
clazz.getPackage() | Package | 获取包信息 | String.class.getPackage() | 
clazz.getModifiers() | int | 获取修饰符(需用 Modifier 解析) | Modifier.isPublic(modifiers) | 
clazz.getSuperclass() | Class<?> | 获取父类 | Integer.class.getSuperclass() | 
clazz.getInterfaces() | Class<?>[] | 获取实现的接口 | List.class.getInterfaces() | 
2. 常⽤获得类相关的⽅法:

3. 获取注解(Annotation)
| 方法 | 返回值 | 用途 | 示例 | 
|---|---|---|---|
clazz.getAnnotations() | Annotation[] | 获取类上的所有注解 | clazz.getAnnotations() | 
clazz.getAnnotation(注解类) | Annotation | 获取类上的指定注解 | clazz.getAnnotation(Deprecated.class) | 
field.getAnnotations() | Annotation[] | 获取字段上的所有注解 | field.getAnnotations() | 
method.getAnnotations() | Annotation[] | 获取方法上的所有注解 | method.getAnnotations() | 
constructor.getAnnotations() | Annotation[] | 获取构造方法上的所有注解 | constructor.getAnnotations() | 
4. 获取构造方法(Constructor)
| 方法 | 返回值 | 用途 | 示例 | 
|---|---|---|---|
clazz.getDeclaredConstructors() | Constructor<?>[] | 获取所有声明的构造方法(包括私有) | clazz.getDeclaredConstructors() | 
clazz.getConstructors() | Constructor<?>[] | 获取所有公共构造方法 | clazz.getConstructors() | 
clazz.getDeclaredConstructor(参数类型...) | Constructor<?> | 获取指定参数类型的构造方法(包括私有) | clazz.getDeclaredConstructor(String.class) | 
clazz.getConstructor(参数类型...) | Constructor<?> | 获取指定参数类型的公共构造方法 | clazz.getConstructor() | 
constructor.setAccessible(true) | void | 设置私有构造方法可访问 | constructor.setAccessible(true) | 
constructor.newInstance(参数...) | Object | 通过构造方法创建实例 | constructor.newInstance("Tom") | 
5. 获取属性(Field)
| 方法 | 返回值 | 用途 | 示例 | 
|---|---|---|---|
clazz.getDeclaredFields() | Field[] | 获取所有声明的属性(包括私有) | clazz.getDeclaredFields() | 
clazz.getFields() | Field[] | 获取所有公共属性(包括继承的) | clazz.getFields() | 
clazz.getDeclaredField("name") | Field | 获取指定名称的属性(包括私有) | clazz.getDeclaredField("age") | 
clazz.getField("name") | Field | 获取指定名称的公共属性 | clazz.getField("name") | 
field.setAccessible(true) | void | 设置私有属性可访问 | field.setAccessible(true) | 
field.get(obj) | Object | 获取属性值 | field.get(user) | 
field.set(obj, value) | void | 设置属性值 | field.set(user, "Tom") | 
6. 获取方法(Method)
| 方法 | 返回值 | 用途 | 示例 | 
|---|---|---|---|
clazz.getDeclaredMethods() | Method[] | 获取所有声明的方法(包括私有) | clazz.getDeclaredMethods() | 
clazz.getMethods() | Method[] | 获取所有公共方法(包括继承的) | clazz.getMethods() | 
clazz.getDeclaredMethod("方法名", 参数类型...) | Method | 获取指定方法(包括私有) | clazz.getDeclaredMethod("setName", String.class) | 
clazz.getMethod("方法名", 参数类型...) | Method | 获取指定公共方法 | clazz.getMethod("toString") | 
method.setAccessible(true) | void | 设置私有方法可访问 | method.setAccessible(true) | 
method.invoke(obj, 参数...) | Object | 调用方法 | method.invoke(user, "Tom") | 
package reflection;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class Test{//类的实例化public static void reflectNewInstance(){try{Class<?> classStudent = Class.forName("reflection.Student");Object objectStudent = classStudent.newInstance();//Student student = (Student) objectStudent;System.out.println("获得学生对象:"+objectStudent);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}//获取类的公有(public)带一个参数构造方法并实例化public static void reflectPublicConstructor(){try{Class<?> classStudent = Class.forName("reflection.Student");//获取类的公有(public)无参构造方法Constructor<?> con = classStudent.getConstructor(String.class);//利用构造方法进行实例化Object studentNewInstance = con.newInstance("wangwu");//Student student = (Student) studentNewInstance;System.out.println("获得公有带一个参数构造方法并修改姓名:"+studentNewInstance);} catch (Exception e) {throw new RuntimeException(e);}}//获取类的私有(private)带一个参数构造方法并实例化public static void reflectPrivateConstructor(){try{Class<?> classStudnt = Class.forName("reflection.Student");//获取类的私有(private)带一个参数构造方法Constructor<?> con = classStudnt.getDeclaredConstructor(int.class);//绕过 Java 的访问控制检查,允许你访问或调用原本不可见的成员(如 private 构造方法、方法或字段)。con.setAccessible(true);//实例化Object studentNewInstance = con.newInstance(20);System.out.println("获得私有带一个参数构造方法并修改年龄:"+studentNewInstance);} catch (Exception e) {throw new RuntimeException(e);}}//获取类的所有构造方法并实例化public static void reflectionConstructor(){try{Class<?> classStudent = Class.forName("reflection.Student");//取类的所有构造方法Constructor<?>[] con = classStudent.getDeclaredConstructors();//使所有构造方法绕过 Java 的访问控制检查,允许访问或调用原本不可见的成员for(Constructor<?> constructor:con){constructor.setAccessible(true);}//实例化Object s1 = con[3].newInstance();Object s2 = con[0].newInstance("lihua",23);System.out.println("获得公有带一个参数构造方法并修改姓名:"+s1);System.out.println("获得私有带两个参数构造方法并修改姓名和年龄:"+s2);} catch (Exception e) {throw new RuntimeException(e);}}//获取私有属性public static void reflectPrivateField(){try {Class<?> classStudent = Class.forName("reflection.Student");//实例化Object s1 = classStudent.newInstance();//获取私有属性Field field = classStudent.getDeclaredField("name");field.setAccessible(true);//修改私有属性field.set(s1,"xh");//获取修改后的私有属性String name = (String) field.get(s1);System.out.println("修改之后的私有属性:"+name);} catch (Exception e) {throw new RuntimeException(e);}}//获取私有方法public static void reflectPrivateMethod(){try {Class<?> classStudent = Class.forName("reflection.Student");//获取私有方法Method method = classStudent.getDeclaredMethod("eat",String.class);System.out.println("获取私有⽅法的⽅法名为:"+method.getName());method.setAccessible(true);//实例化Object s1 = classStudent.newInstance();//方法调用method.invoke(s1,"vegetable");} catch (Exception e) {throw new RuntimeException(e);}}public static void main(String[] args) {reflectNewInstance();reflectPublicConstructor();reflectPrivateConstructor();reflectionConstructor();reflectPrivateField(); 
3. 反射优点和缺点
1. 优点
1. 动态性(运行时操作类)
无需在编译时确定类,可以在运行时动态加载类、调用方法、访问属性。
2. 访问私有成员
通过
setAccessible(true)可以绕过 Java 的访问控制,访问private方法、属性和构造方法。3. 泛型擦除时获取真实类型
由于 Java 泛型在运行时会被擦除(Type Erasure),可以通过反射获取泛型的实际类型。
4. 注解处理
反射可以读取类、方法、字段上的注解,实现灵活的配置和扩展。
5. 动态创建和操作对象
可以在运行时动态创建对象、调用方法,适用于 高度灵活 的场景。
2. 缺点
大家都说 Java 反射效率低,你知道原因在哪里么_慕课手记
1. 性能较差
-  
反射比直接调用慢 10~100 倍,主要因为:
-  
JVM 无法优化反射调用(如方法内联)。
 -  
需要额外的安全检查(如
AccessibleObject.setAccessible())。 
 -  
 -  
影响场景:
-  
高频调用的代码(如循环内使用反射)。
 -  
高性能要求的系统(如交易系统、游戏引擎)。
 
 -  
 
2. 破坏封装性
-  
setAccessible(true)可以绕过private限制,导致:-  
代码安全性降低(恶意代码可能篡改私有数据)。
 -  
破坏面向对象的封装原则(如
final字段被修改)。 
 -  
 
3. 代码可读性和维护性差
-  
反射代码通常 冗长、难以调试,IDE 也无法提供智能提示。
 
4. 编译时检查失效
-  
反射调用在 编译期不会检查错误(如方法名拼写错误、参数类型不匹配),只能在运行时抛出异常。
 
5. 安全问题
-  
反射可以 绕过安全管理器(SecurityManager),可能导致:
-  
私有 API 被非法调用。
 -  
敏感数据泄露(如通过反射获取
Password字段)。 
 -  
 
getDeclaredMethods()、getDeclaredFields() 或 getDeclaredConstructors() 获取的方法、属性或构造方法的顺序是不确定的,具体顺序取决于 JVM 的实现(如 OpenJDK 和 Oracle JDK 可能不同)。所以我们可以使用 Arrays.sort 按名称、修饰符、参数类型等自行排序。 
| 优点 | 缺点 | 
|---|---|
| 动态加载和操作类 | 性能差(比直接调用慢 10~100 倍) | 
| 可访问私有成员 | 破坏封装性 | 
| 支持泛型擦除时的类型获取 | 代码可读性差 | 
| 强大的注解处理能力 | 编译时检查失效 | 
| 适用于框架和灵活架构 | 可能引发安全问题 | 
2. 枚举
1. 背景及定义
public static final int RED = 1;
public static final int GREEN = 2;
public static final int WHITE = 3; 
 2. Enum 类的常⽤⽅法
 
3. 关键点:
-  
枚举常量必须放在枚举类的最前面,并用逗号
,分隔,最后一个常量后用分号; ,后面才能定义字段和方法。。 -  
枚举的构造方法是自动调用的,构造方法必须与枚举常量的参数匹配(无参常量 → 无参构造方法;带参常量 → 带参构造方法)。
 -  
构造方法默认是
private,不能声明为public或protected(因为枚举的实例只能由枚举自身创建)。 -  
构造方法调用是隐式的,当枚举类被 JVM 加载时,所有枚举常量会被初始化,并自动调用对应的构造方法(不能手动调用构造方法),例如 WHITE("White",5);
 -  
枚举常量是单例的,构造方法只会被调用一次:
 -  
每个枚举常量本质上是一个静态实例,相当于:
 
public static final EnumDom WHITE = new EnumDom("White",10); (枚举类型(enum)的构造方法默认是私有的(private),这意味着你不能直接使用new关键字来创建枚举实例。 枚举常量必须通过枚举类型本身隐式创建。例如 WHITE("White",5);)
7. 在Java中,枚举常量的引用不可变,但若设计不当(含非 final 字段),其内部状态可能被修改。强烈建议将枚举设计为完全不可变。
4. 使用
public enum EnumDom {RED,//无参枚举常量GREEN("Green"),//带一个参数的枚举常量WHITE("White",5);//带两个参数的枚举常量//枚举类型(enum)的构造方法默认是私有的(private),这意味着你不能直接使用new关键字来创建枚举实例。// 枚举常量必须通过枚举类型本身隐式创建。//public static final EnumDom WHITE = new EnumDom("White",10);//构造方法必须匹配枚举常量的参数类型和数量//无参构造方法(可不写,java会自动提供)private EnumDom(){}public String name;public int code;//带一个参数的构造方法private EnumDom(String name){this.name = name;}//带两个参数的构造方法private EnumDom(String name,int code){this.name = name;this.code = code;System.out.println(this.name+" "+this.code);}//方法private void color(String name){this.name = name;//非final字段,可以修改System.out.println(this.name);}//    @Override
//    public String toString() {
//        return "EnumDom{" +
//                "name='" + name + '\'' +
//                ", code=" + code +
//                '}';
//    }public static void main(String[] args) {//直接调用枚举常量//枚举常量在类加载时通过构造方法初始化,且仅初始化一次(线程安全)。EnumDom w1 = EnumDom.WHITE;EnumDom w2 = EnumDom.WHITE;System.out.println(w1);System.out.println(w2);System.out.println(w1==w2);//同一个WHITE//以数组形式返回枚举类型的所有成员EnumDom[] enumDom = EnumDom.values();for(EnumDom e: enumDom){System.out.print(e+" ");//获取枚举成员的索引位置System.out.println(e.ordinal());}//将普通字符串转换为枚举实例EnumDom e1 = EnumDom.valueOf("RED");System.out.println(e1);//比较两个枚举成员在定义时的顺序System.out.println(enumDom[0].compareTo(enumDom[2]));//方法调用enumDom[0].color("red");enumDom[1].color("green");}
} 
5. 枚举和反射
通过反射我们可以获取枚举常量本身,非final字段,方法,构造方法信息,注解信息
不可以获取/操作的内容:
-  
无法通过构造方法创建新的枚举实例
-  
尝试反射调用构造方法会抛出
IllegalArgumentException: Cannot reflectively create enum objects 
 -  
 -  
无法修改final字段(除非使用特殊技巧)
-  
常规反射无法修改final字段
 -  
需要先修改Field的modifiers字段(不推荐)
 
 -  
 -  
无法获取编译器生成的某些特殊方法
-  
如
values()和valueOf()方法在字节码中是编译器生成的 
 -  
 -  
无法改变枚举常量的顺序(ordinal)
-  
ordinal是final的且由编译器决定
 
 -  
 -  
无法删除或添加枚举常量
-  
枚举集合在运行时是固定的
 
 -  
 
package enumeration;import java.lang.reflect.Constructor;
import java.lang.reflect.Method;public class Test {public static void main(String[] args) {try{Class<?> clazz = Class.forName("enumeration.EnumDom");//获取所有枚举常量并调用对应的构造方法Object[] enumDoms = clazz.getEnumConstants();//打印所有枚举成员for(Object em :enumDoms ){System.out.println(em);}//获取枚举构造方法Constructor<?>[] con = clazz.getDeclaredConstructors();for(Constructor<?> constructor:con){constructor.setAccessible(true);}//获取指定枚举构造方法,包含继承的Enum的构造方法的参数Constructor<?> con1 = clazz.getDeclaredConstructor(String.class,int.class,String.class);//无法通过反射创建新实例//Object e1 = con[0].newInstance();//抛出异常 Cannot reflectively create enum objects//System.out.println(e1);//获取枚举类的方法Method method = clazz.getDeclaredMethod("color",String.class);method.setAccessible(true);method.invoke(EnumDom.RED,"red");//在反射中可以直接调用枚举常量method.invoke(enumDoms[1],"green");} catch (Exception e) {throw new RuntimeException(e);}}
} 
3. Lambda表达式
1. 背景
2. Lambda表达式的语法
(parameters) -> expression 或(parameters) ->{ statements; }
Lambda表达式由三部分组成:1. paramaters:类似⽅法中的形参列表,这⾥的参数是函数式接⼝⾥的参数(可以包含零个或多个) 。这⾥的参数类型可以明确的声明也可不声明⽽由JVM隐含的推断。另外当只有⼀个参数且无参数类型时可以省略掉圆括号。2. ->:可理解为“被⽤于”的意思,将参数与方法体分开3. ⽅法体:可以是单个表达式或代码块,是函数式接⼝⾥⽅法的实现。代码块可返回⼀个值或者什么都不返回,这⾥的代码块等同于⽅法的⽅法体。如果是表达式,也可以返回⼀个值或者什么都不返回。单个表达式或不用return关键字 直接返回表达式结果可以省略大括号{}。
3. 函数式接⼝
//⽆返回值⽆参数
@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);
}
public class Test {public static void main(String[] args) {//内部类NoParameterNoReturn noParameterNoReturn1 = new NoParameterNoReturn() {@Overridepublic void test() {System.out.println("⽆返回值⽆参数1");}};noParameterNoReturn1.test();NoParameterNoReturn noParameterNoReturn =()->System.out.println("⽆返回值⽆参数2");noParameterNoReturn.test();//当只有一个参数时,无参数类型,可以不需要()OneParameterNoReturn oneParameterNoReturn = x->{System.out.print("⽆返回值一个参数:");System.out.println(x);};oneParameterNoReturn.test(10);MoreParameterNoReturn moreParameterNoReturn = (x,y)->{System.out.print("⽆返回值多个参数:");System.out.println(x+y);};moreParameterNoReturn.test(10,20);//当 Lambda 体不使用 return 语句时,直接返回表达式结果不需要大括号NoParameterReturn noParameterReturn = ()->100;System.out.print("有返回值无参数:");System.out.println(noParameterReturn.test());//当 Lambda 体使用 return 语句时,必须使用大括号 {} 包裹代码块OneParameterReturn oneParameterReturn = (int x)->{return x;};System.out.print("有返回值一个参数:");System.out.println(oneParameterReturn.test(200));MoreParameterReturn moreParameterReturn = (x,y)->{System.out.print("有返回值多个参数:");return x+y;};System.out.println(moreParameterReturn.test(300,400));}
} 
4. Lambda 表达式和匿名内部类
| 特性 | Lambda 表达式 | 匿名内部类 | 
|---|---|---|
| 引入版本 | Java 8 | Java 1.1 | 
| 语法简洁性 | 更简洁 | 相对冗长 | 
| 适用场景 | 仅适用于函数式接口(单个抽象方法) | 适用于任何接口或抽象类 | 
| 生成类文件 | 不生成额外.class文件 | 生成外部类$数字.class文件 | 
| this关键字含义 | 指向外部类实例 | 指向内部类自身实例 | 
1. 变量捕获
Lambda 表达式可以捕获外部作用域的变量,这种特性称为"变量捕获"(Variable Capture)。这是 Lambda 表达式强大功能之一,但也需要遵循特定规则。
1. 局部变量捕获
Lambda 可以捕获方法中的局部变量,但有严格限制:
-  
被捕获的局部变量必须是 final 或 effectively final(即初始化后不再修改)
 -  
原因:Lambda 可能在原始变量生命周期结束后执行,Java 需要保证值的一致性
 
2. 实例变量捕获
Lambda 可以自由捕获所在类的实例变量:
-  
可以读取
 -  
可以修改
 -  
不需要是 final
 
3. 静态变量捕获
Lambda 可以自由捕获静态变量:
-  
可以读取
 -  
可以修改
 -  
不需要是 final
 
| 变量类型 | 可读性 | 可修改性 | final要求 | 
|---|---|---|---|
| 局部变量 | 是 | 否 | 必须effectively final | 
| 实例变量 | 是 | 是 | 不需要 | 
| 静态变量 | 是 | 是 | 不需要 | 
interface Student{void fun();
}
public class Test2 {public int a = 10;//实例变量public static int b = 20;//静态变量public void fuction(){int c = 30;//局部变量Student student = ()->{a = 40;b = 50;//被捕获的局部变量必须final 或 effectively final(即初始化后不再修改)//c = 60;//err System.out.println(a);//40System.out.println(b);//50System.out.println(c);//30};student.fun();}public static void main(String[] args) {Test2 test2 = new Test2();test2.fuction();}
}
 5. Lambda在集合当中的使⽤