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

Java反射机制详细笔记

目录

引言

基础概念

什么是反射?

反射的两大核心操作

反射涉及的主要类

主要特性

反射的五大特性

详细用法

1. 获取Class对象(三种方式)

三种方式的对比

2. 通过反射获取构造方法

相关API总结

Constructor类的常用方法

代码示例

3. 通过反射获取成员变量

相关API总结

Field类的常用方法

代码示例

4. 通过反射获取成员方法

相关API总结

Method类的常用方法

代码示例

5. 反射操作数组

实际应用场景

1. 实现简单的对象工厂

2. 实现通用的对象拷贝工具

3. 实现简单的依赖注入

4. 实现注解处理器

注意事项和最佳实践

性能优化

安全性考虑

异常处理最佳实践

与相关技术的对比

反射 vs 正常调用

反射 vs 动态代理 vs 字节码操作

面试常见问题

Q1: 什么是反射?反射的作用是什么?

Q2: 获取Class对象的三种方式及其区别?

Q3: 为什么反射会破坏封装性?如何看待这个问题?

Q4: 反射的性能问题如何优化?

Q5: getDeclaredMethod和getMethod的区别?

Q6: 反射在实际开发中的应用场景?

Q7: 如何通过反射调用可变参数的方法?

Q8: 反射和注解的关系?

总结

核心知识点梳理

使用建议

学习路径建议


引言

想象你正在开发一个通用的Excel导入工具,需要将Excel数据自动填充到不同的Java对象中。问题是:你事先并不知道用户会传入什么类型的对象。这时候,Java反射机制就派上用场了。

反射(Reflection)是Java语言的一个重要特性,它允许程序在运行时动态地获取类的信息,并能够动态地创建对象、调用方法、访问属性等。简单来说,反射就是"让程序在运行时拥有检查和操作自身的能力"。

基础概念

什么是反射?

反射允许对成员变量、成员方法和构造方法的信息进行编程访问。

反射机制的核心是Class类,每个Java类在JVM中都有一个对应的Class对象,通过这个对象可以获取类的所有信息。

反射的两大核心操作

  1. 获取:获取类的各种组成部分(构造方法、成员变量、成员方法)
  2. 解剖:分析这些组成部分的详细信息(修饰符、名称、参数、返回值等)并进行操作

反射涉及的主要类

类名作用所在包
Class代表一个类的字节码对象java.lang
Constructor代表类的构造方法java.lang.reflect
Field代表类的成员变量java.lang.reflect
Method代表类的成员方法java.lang.reflect
Modifier代表修饰符(public、private等)java.lang.reflect

主要特性

反射的五大特性

  1. 运行时类型识别 - 在运行时判断对象所属的类
  2. 动态创建对象 - 在运行时创建任意类的对象
  3. 动态调用方法 - 在运行时调用任意对象的方法
  4. 动态访问属性 - 在运行时访问和修改对象的属性
  5. 突破访问限制 - 可以访问private成员(需要设置权限)

详细用法

1. 获取Class对象(三种方式)

public class GetClassDemo {public static void main(String[] args) throws ClassNotFoundException {// 方式1:Class.forName("全类名")// 应用场景:配置文件中指定类名,动态加载// 注意:会触发类的静态代码块执行Class<?> clazz1 = Class.forName("com.example.Student");// 方式2:类名.class// 应用场景:参数传递,编译时已知类型// 特点:不会触发静态代码块执行Class<Student> clazz2 = Student.class;// 方式3:对象.getClass()// 应用场景:已有对象实例,获取运行时类型Student student = new Student();Class<?> clazz3 = student.getClass();// 验证:同一个类的Class对象是唯一的(单例)System.out.println(clazz1 == clazz2); // trueSystem.out.println(clazz2 == clazz3); // true}
}

三种方式的对比

获取方式使用前提应用场景是否执行静态代码块
Class.forName()知道全限定类名配置文件加载类
类名.class编译时已知类型参数传递
对象.getClass()已有对象实例获取运行时类型否(对象创建时已执行)

2. 通过反射获取构造方法

相关API总结
方法名作用返回值类型
getConstructors()获取所有public构造方法Constructor<?>[]
getDeclaredConstructors()获取所有构造方法(含private)Constructor<?>[]
getConstructor(Class<?>... parameterTypes)获取指定的public构造方法Constructor<T>
getDeclaredConstructor(Class<?>... parameterTypes)获取指定的构造方法(含private)Constructor<T>
Constructor类的常用方法
方法名作用使用示例
newInstance(Object... initargs)创建对象constructor.newInstance("张三", 20)
setAccessible(boolean flag)设置访问权限constructor.setAccessible(true)
getModifiers()获取修饰符int mod = constructor.getModifiers()
getParameterTypes()获取参数类型Class<?>[] types = constructor.getParameterTypes()
代码示例
public class ConstructorDemo {public static void main(String[] args) throws Exception {Class<Student> clazz = Student.class;// 1. 获取并使用无参构造Constructor<Student> c1 = clazz.getConstructor();Student s1 = c1.newInstance();System.out.println("无参构造创建的对象:" + s1);// 2. 获取并使用有参构造Constructor<Student> c2 = clazz.getConstructor(String.class, int.class);Student s2 = c2.newInstance("张三", 20);System.out.println("有参构造创建的对象:" + s2);// 3. 获取并使用私有构造Constructor<Student> c3 = clazz.getDeclaredConstructor(String.class);c3.setAccessible(true); // 必须设置,否则抛出IllegalAccessExceptionStudent s3 = c3.newInstance("李四");System.out.println("私有构造创建的对象:" + s3);// 4. 获取所有构造方法的信息Constructor<?>[] constructors = clazz.getDeclaredConstructors();for (Constructor<?> constructor : constructors) {System.out.println("构造方法:" + constructor);System.out.println("参数个数:" + constructor.getParameterCount());System.out.println("修饰符:" + Modifier.toString(constructor.getModifiers()));System.out.println("------------------------");}}
}

3. 通过反射获取成员变量

相关API总结
方法名作用返回值类型
getFields()获取所有public成员变量(含继承)Field[]
getDeclaredFields()获取所有成员变量(不含继承)Field[]
getField(String name)获取指定的public成员变量Field
getDeclaredField(String name)获取指定的成员变量Field
Field类的常用方法
方法名作用使用示例
get(Object obj)获取字段值Object value = field.get(student)
set(Object obj, Object value)设置字段值field.set(student, "新值")
setAccessible(boolean flag)设置访问权限field.setAccessible(true)
getType()获取字段类型Class<?> type = field.getType()
getModifiers()获取修饰符int mod = field.getModifiers()
getName()获取字段名String name = field.getName()
代码示例
public class FieldDemo {public static void main(String[] args) throws Exception {Class<Student> clazz = Student.class;Student student = new Student("王五", 25);// 1. 获取public字段Field nameField = clazz.getField("name"); // name必须是publicString name = (String) nameField.get(student);System.out.println("获取到的name:" + name);// 2. 获取private字段Field ageField = clazz.getDeclaredField("age"); // age是privateageField.setAccessible(true); // 关键步骤!int age = (int) ageField.get(student);System.out.println("获取到的age:" + age);// 3. 修改字段值nameField.set(student, "赵六");ageField.set(student, 30);System.out.println("修改后的对象:" + student);// 4. 获取所有字段信息Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {System.out.println("字段名:" + field.getName());System.out.println("字段类型:" + field.getType().getSimpleName());System.out.println("是否可访问:" + field.isAccessible());System.out.println("修饰符:" + Modifier.toString(field.getModifiers()));System.out.println("------------------------");}// 5. 获取字段的泛型类型(如果是泛型字段)Field listField = clazz.getDeclaredField("scores"); // List<Integer> scoresType genericType = listField.getGenericType();if (genericType instanceof ParameterizedType) {ParameterizedType pt = (ParameterizedType) genericType;Type[] actualTypes = pt.getActualTypeArguments();System.out.println("泛型类型:" + Arrays.toString(actualTypes));}}
}

4. 通过反射获取成员方法

相关API总结
方法名作用返回值类型
getMethods()获取所有public方法(含继承)Method[]
getDeclaredMethods()获取所有方法(不含继承)Method[]
getMethod(String name, Class<?>... parameterTypes)获取指定的public方法Method
getDeclaredMethod(String name, Class<?>... parameterTypes)获取指定的方法Method
Method类的常用方法
方法名作用使用示例
invoke(Object obj, Object... args)调用方法Object result = method.invoke(student, "参数")
setAccessible(boolean flag)设置访问权限method.setAccessible(true)
getReturnType()获取返回值类型Class<?> returnType = method.getReturnType()
getParameterTypes()获取参数类型数组Class<?>[] paramTypes = method.getParameterTypes()
getModifiers()获取修饰符int mod = method.getModifiers()
getName()获取方法名String name = method.getName()
getExceptionTypes()获取异常类型Class<?>[] exceptions = method.getExceptionTypes()
代码示例
public class MethodDemo {public static void main(String[] args) throws Exception {Class<Student> clazz = Student.class;Student student = new Student("张三", 20);// 1. 调用无参方法Method getNameMethod = clazz.getMethod("getName");String name = (String) getNameMethod.invoke(student);System.out.println("getName()返回值:" + name);// 2. 调用有参方法Method setNameMethod = clazz.getMethod("setName", String.class);setNameMethod.invoke(student, "李四"); // 返回值是void,所以不接收System.out.println("调用setName后:" + student.getName());// 3. 调用私有方法Method privateMethod = clazz.getDeclaredMethod("study", String.class);privateMethod.setAccessible(true);String result = (String) privateMethod.invoke(student, "Java");System.out.println("私有方法返回值:" + result);// 4. 调用静态方法Method staticMethod = clazz.getMethod("getSchool");String school = (String) staticMethod.invoke(null); // 静态方法传nullSystem.out.println("静态方法返回值:" + school);// 5. 获取方法的详细信息Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {System.out.println("\n方法名:" + method.getName());System.out.println("返回类型:" + method.getReturnType().getSimpleName());// 参数信息Parameter[] parameters = method.getParameters();System.out.print("参数列表:");for (Parameter param : parameters) {System.out.print(param.getType().getSimpleName() + " " + param.getName() + " ");}// 异常信息Class<?>[] exceptions = method.getExceptionTypes();if (exceptions.length > 0) {System.out.print("\n抛出异常:");for (Class<?> ex : exceptions) {System.out.print(ex.getSimpleName() + " ");}}// 修饰符System.out.println("\n修饰符:" + Modifier.toString(method.getModifiers()));System.out.println("------------------------");}}
}

5. 反射操作数组

public class ArrayReflectDemo {public static void main(String[] args) {// 1. 创建数组int[] intArray = (int[]) Array.newInstance(int.class, 5);String[] strArray = (String[]) Array.newInstance(String.class, 3);// 2. 设置数组元素Array.set(intArray, 0, 100);Array.set(intArray, 1, 200);Array.set(strArray, 0, "Hello");Array.set(strArray, 1, "World");// 3. 获取数组元素int firstInt = Array.getInt(intArray, 0);String firstStr = (String) Array.get(strArray, 0);System.out.println("第一个int:" + firstInt);System.out.println("第一个String:" + firstStr);// 4. 获取数组长度int intLength = Array.getLength(intArray);int strLength = Array.getLength(strArray);System.out.println("int数组长度:" + intLength);System.out.println("String数组长度:" + strLength);// 5. 创建多维数组int[][] matrix = (int[][]) Array.newInstance(int.class, 3, 3);matrix[0][0] = 1;matrix[1][1] = 5;matrix[2][2] = 9;// 6. 判断是否是数组System.out.println("intArray是数组吗?" + intArray.getClass().isArray());System.out.println("matrix是数组吗?" + matrix.getClass().isArray());// 7. 获取数组的组件类型Class<?> componentType = intArray.getClass().getComponentType();System.out.println("数组元素类型:" + componentType);}
}

实际应用场景

1. 实现简单的对象工厂

public class ObjectFactory {// 对象缓存池private static final Map<String, Object> objectPool = new HashMap<>();/*** 根据类名创建对象(单例)*/public static Object getInstance(String className) {try {// 从缓存中获取Object instance = objectPool.get(className);if (instance != null) {return instance;}// 使用反射创建新对象Class<?> clazz = Class.forName(className);instance = clazz.newInstance();objectPool.put(className, instance);return instance;} catch (Exception e) {throw new RuntimeException("创建对象失败:" + className, e);}}/*** 根据类名和参数创建对象*/public static Object createInstance(String className, Object... args) {try {Class<?> clazz = Class.forName(className);// 获取参数类型Class<?>[] paramTypes = new Class[args.length];for (int i = 0; i < args.length; i++) {paramTypes[i] = args[i].getClass();}// 获取对应的构造方法Constructor<?> constructor = clazz.getConstructor(paramTypes);return constructor.newInstance(args);} catch (Exception e) {throw new RuntimeException("创建对象失败:" + className, e);}}
}

2. 实现通用的对象拷贝工具

public class BeanUtils {/*** 对象属性拷贝(浅拷贝)*/public static void copyProperties(Object source, Object target) {if (source == null || target == null) {return;}try {// 获取源对象的所有字段Class<?> sourceClass = source.getClass();Field[] sourceFields = sourceClass.getDeclaredFields();// 获取目标对象的类Class<?> targetClass = target.getClass();for (Field sourceField : sourceFields) {// 忽略静态字段和final字段int modifiers = sourceField.getModifiers();if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {continue;}try {// 获取目标对象的对应字段Field targetField = targetClass.getDeclaredField(sourceField.getName());// 检查类型是否匹配if (!targetField.getType().equals(sourceField.getType())) {continue;}// 设置可访问sourceField.setAccessible(true);targetField.setAccessible(true);// 拷贝值Object value = sourceField.get(source);targetField.set(target, value);} catch (NoSuchFieldException e) {// 目标对象没有对应字段,跳过continue;}}} catch (Exception e) {throw new RuntimeException("属性拷贝失败", e);}}/*** 将对象转换为Map*/public static Map<String, Object> objectToMap(Object obj) {Map<String, Object> map = new HashMap<>();if (obj == null) {return map;}try {Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 忽略静态字段if (Modifier.isStatic(field.getModifiers())) {continue;}field.setAccessible(true);String name = field.getName();Object value = field.get(obj);map.put(name, value);}} catch (Exception e) {throw new RuntimeException("对象转Map失败", e);}return map;}
}

3. 实现简单的依赖注入

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Inject {String value() default "";
}// 简单的IoC容器
public class SimpleIoC {// Bean容器private Map<String, Object> beanContainer = new HashMap<>();// 注册Beanpublic void registerBean(String beanName, Object bean) {beanContainer.put(beanName, bean);}// 注册Bean(使用类名作为beanName)public void registerBean(Object bean) {String beanName = bean.getClass().getSimpleName();beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);registerBean(beanName, bean);}// 依赖注入public void injectDependencies(Object target) {try {Class<?> clazz = target.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 检查是否有@Inject注解if (field.isAnnotationPresent(Inject.class)) {Inject inject = field.getAnnotation(Inject.class);String beanName = inject.value();// 如果没有指定beanName,使用字段名if (beanName.isEmpty()) {beanName = field.getName();}// 从容器中获取BeanObject bean = beanContainer.get(beanName);if (bean != null) {field.setAccessible(true);field.set(target, bean);}}}} catch (Exception e) {throw new RuntimeException("依赖注入失败", e);}}
}// 使用示例
class UserService {public void saveUser(String username) {System.out.println("保存用户:" + username);}
}class UserController {@Injectprivate UserService userService;public void register(String username) {userService.saveUser(username);}
}// 测试
public class IoCTest {public static void main(String[] args) {SimpleIoC container = new SimpleIoC();// 注册BeanUserService userService = new UserService();container.registerBean(userService);// 创建Controller并注入依赖UserController controller = new UserController();container.injectDependencies(controller);// 使用controller.register("张三");}
}

4. 实现注解处理器

// 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Log {String value() default "";
}@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Permission {String[] roles() default {};
}// 注解处理器
public class AnnotationProcessor {/*** 处理方法上的注解*/public static void processMethodAnnotations(Object obj) {Class<?> clazz = obj.getClass();Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {// 处理@Log注解if (method.isAnnotationPresent(Log.class)) {Log log = method.getAnnotation(Log.class);System.out.println("方法 " + method.getName() + " 有@Log注解,值为:" + log.value());}// 处理@Permission注解if (method.isAnnotationPresent(Permission.class)) {Permission permission = method.getAnnotation(Permission.class);System.out.println("方法 " + method.getName() + " 需要权限:" + Arrays.toString(permission.roles()));}}}/*** 执行带有指定注解的方法*/public static void invokeAnnotatedMethods(Object obj, Class<? extends Annotation> annotationClass) {try {Class<?> clazz = obj.getClass();Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {if (method.isAnnotationPresent(annotationClass)) {method.setAccessible(true);// 处理无参方法if (method.getParameterCount() == 0) {method.invoke(obj);}}}} catch (Exception e) {throw new RuntimeException("执行注解方法失败", e);}}
}// 使用示例
class BusinessService {@Log("用户登录")@Permission(roles = {"admin", "user"})public void login(String username) {System.out.println(username + " 登录成功");}@Log("数据删除")@Permission(roles = {"admin"})public void deleteData(int id) {System.out.println("删除数据:" + id);}
}

注意事项和最佳实践

性能优化

  1. 缓存反射对象
public class ReflectionCache {// 缓存Class对象private static final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();// 缓存Method对象private static final Map<String, Method> methodCache = new ConcurrentHashMap<>();// 缓存Field对象private static final Map<String, Field> fieldCache = new ConcurrentHashMap<>();public static Class<?> getClass(String className) throws ClassNotFoundException {return classCache.computeIfAbsent(className, k -> {try {return Class.forName(k);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}});}public static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {String key = clazz.getName() + "." + methodName + Arrays.toString(paramTypes);return methodCache.computeIfAbsent(key, k -> {try {return clazz.getMethod(methodName, paramTypes);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}});}
}
  1. 使用setAccessible(true)的注意事项
// setAccessible不仅可以访问私有成员,还能提升性能
// 因为跳过了Java的访问检查
Method method = clazz.getDeclaredMethod("privateMethod");
method.setAccessible(true); // 提升约10%性能

安全性考虑

  1. 使用安全管理器限制反射
// 在安全敏感的环境中,可以通过安全管理器限制反射的使用
System.setSecurityManager(new SecurityManager() {@Overridepublic void checkPermission(Permission perm) {if (perm instanceof ReflectPermission) {throw new SecurityException("反射操作被禁止");}}
});
  1. 防止反射破坏单例模式
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {// 防止反射创建多个实例if (INSTANCE != null) {throw new RuntimeException("不允许创建多个实例");}}public static Singleton getInstance() {return INSTANCE;}
}

异常处理最佳实践

public class ReflectionUtil {/*** 安全地调用方法*/public static Object invokeMethod(Object obj, String methodName, Object... args) {try {Class<?> clazz = obj.getClass();// 获取参数类型Class<?>[] paramTypes = new Class[args.length];for (int i = 0; i < args.length; i++) {paramTypes[i] = args[i].getClass();}Method method = clazz.getMethod(methodName, paramTypes);return method.invoke(obj, args);} catch (NoSuchMethodException e) {System.err.println("方法不存在:" + methodName);} catch (IllegalAccessException e) {System.err.println("访问权限不足:" + methodName);} catch (InvocationTargetException e) {System.err.println("方法执行异常:" + e.getCause());} catch (Exception e) {System.err.println("未知异常:" + e.getMessage());}return null;}
}

与相关技术的对比

反射 vs 正常调用

对比项正常调用反射调用
性能快(编译期优化)慢(运行时解析)
类型安全编译时检查运行时检查
代码可读性
灵活性低(编译时确定)高(运行时确定)
使用难度简单复杂
调试难度容易困难

反射 vs 动态代理 vs 字节码操作

技术原理性能使用场景典型框架
反射运行时获取类信息框架开发、通用工具Spring IoC
动态代理基于反射生成代理类中等AOP、事务管理Spring AOP
字节码操作直接修改字节码性能敏感场景CGLIB、ASM

面试常见问题

Q1: 什么是反射?反射的作用是什么?

答: 反射是Java在运行时动态获取类信息和操作对象的机制。主要作用:

  • 在运行时判断对象所属的类
  • 在运行时创建对象
  • 在运行时调用对象的方法
  • 在运行时访问和修改对象的属性
  • 实现框架的通用性和灵活性

Q2: 获取Class对象的三种方式及其区别?

答:

  1. Class.forName("全类名"):需要知道类的全限定名,会初始化类(执行静态代码块)
  2. 类名.class:需要导入类包,不会初始化类
  3. 对象.getClass():需要有对象实例,获取的是运行时真实类型

Q3: 为什么反射会破坏封装性?如何看待这个问题?

答: 反射可以通过setAccessible(true)访问私有成员,确实破坏了封装性。但这是一种权衡:

  • 优点:提供了强大的动态能力,使框架开发成为可能
  • 缺点:可能导致安全问题和代码维护困难
  • 建议:在框架开发中合理使用,业务代码中尽量避免

Q4: 反射的性能问题如何优化?

答:

  1. 缓存Class、Method、Field等反射对象
  2. 使用setAccessible(true)跳过权限检查
  3. 对于频繁调用的场景,考虑使用代码生成替代反射
  4. JDK 7+可以使用MethodHandle

Q5: getDeclaredMethod和getMethod的区别?

答:

  • getMethod:只能获取public方法,包括从父类继承的
  • getDeclaredMethod:可以获取所有访问权限的方法,但只限于当前类声明的,不包括继承的

Q6: 反射在实际开发中的应用场景?

答:

  1. Spring框架的IoC容器和依赖注入
  2. MyBatis的ORM映射
  3. JUnit的单元测试框架
  4. JSON序列化工具(如Gson、Jackson)
  5. RPC框架的方法调用

Q7: 如何通过反射调用可变参数的方法?

答:

// 可变参数在反射中被当作数组处理
Method method = clazz.getMethod("varArgsMethod", String[].class);
// 注意:需要将可变参数包装成数组
method.invoke(obj, new Object[]{new String[]{"arg1", "arg2", "arg3"}});

Q8: 反射和注解的关系?

答: 注解本身只是元数据,需要通过反射来读取和处理:

  • 运行时注解必须通过反射获取
  • 反射提供了isAnnotationPresent()getAnnotation()等方法
  • 大部分注解处理框架都基于反射实现

总结

核心知识点梳理

  1. 反射的本质:在运行时动态获取类信息并操作的能力
  2. 四大核心类:Class、Constructor、Field、Method
  3. 三种获取Class的方式:forName()、.class、getClass()
  4. 关键操作:setAccessible(true)突破访问限制
  5. 性能问题:比直接调用慢10-100倍,需要优化

使用建议

什么时候用反射:

  • 开发通用框架或工具
  • 需要动态加载类
  • 处理运行时注解
  • 实现插件化架构

什么时候不用反射:

  • 普通的业务逻辑
  • 性能敏感的场景
  • 能用普通OOP解决的问题

学习路径建议

  1. 入门阶段:掌握基本API的使用
  2. 进阶阶段:理解反射在框架中的应用
  3. 高级阶段:学习性能优化和安全防护
  4. 实战阶段:尝试用反射实现小型框架

记住:反射是一把双刃剑,合理使用能让代码更加灵活,滥用则会导致代码难以维护。在实际开发中,应该优先考虑常规的面向对象设计,只在确实需要动态性的场景下才使用反射。

http://www.xdnf.cn/news/8767.html

相关文章:

  • 项目管理学习-CSPM4(2)
  • 代码随想录第42天:图论3
  • 嵌入式硬件---施密特触发器单稳态触发器多谐振荡器
  • 【Excel VBA 】窗体控件分类
  • 【TDengine源码阅读】举例说明pthread_once_t和PTHREAD_ONCE_INIT
  • STM32 输出比较输出PWM控制呼吸灯小实验(2种实现 铁头山羊与江协科技)
  • Ansible安装
  • C++面向对象编程实战:继承与派生全解析
  • A2A与MCP:差异、协同及企业级应用解析
  • 实战设计模式之访问者模式
  • Javase 基础加强 —— 07 File
  • 云原生安全基石:Linux进程隔离技术详解
  • 2025最新智能优化算法:野燕麦优化算法(Animated Oat Optimization Algorithm, AOO),MATLAB代码
  • JavaSE核心知识点03高级特性03-04(Lambda表达式)
  • 产品迭代与放弃的判断:MVP、PMF 与 Scale Fit 的三重验证
  • VS编码访问Mysql数据库
  • 数据库范式
  • 易贝平台关键字搜索技术深度解析
  • Lesson 21 Mad or not
  • 2024 CKA模拟系统制作 | Step-By-Step | 4、题目搭建-权限控制RBAC
  • 数据库MySQL进阶
  • 【C++】封装红黑树实现 mymap 和 myset
  • 实现Web网站冷启动的全面指南
  • LeetCode 3362.零数组变换 III:贪心+优先队列+差分数组——清晰题解
  • 天猫平台实时商品数据 API 接入方案与开发实践
  • 【时时三省】Python 语言----字符串,列表,元组,字典常用操作异同点
  • Interviews(访谈):业务分析师的“信息开采器”
  • LangGraph 实战指南:长期记忆管理
  • CMSIS-NN:1.简介
  • 【大模型报错解决】cublasLt ran into an error!