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

Java基础知识(十)

类的生命周期:

硬盘阶段

在 Java 开发过程中,硬盘阶段主要涉及 Java 源代码文件和字节码文件在硬盘上的存储。

  • Java 源代码文件(.java):开发人员编写的 Java 代码保存在以.java为扩展名的文件中,这些文件存储在硬盘上。此时的代码是人类可读的高级语言形式,包含了类的定义、方法、属性等内容。例如,定义一个简单的HelloWorld类:

public class HelloWorld {public static void main(String[] args) {System.out.println("Hello, World!");}
}

  • 字节码文件(.class) :使用javac命令对.java文件进行编译,会生成对应的.class字节码文件, 这些字节码文件同样存储在硬盘上。字节码是一种中间形式,它不依赖于具体的操作系统和硬件,是 Java 实现 “一次编写,到处运行” 特性的关键。比如对上述HelloWorld.java编译后,会生成HelloWorld.class文件。

类阶段

类阶段涵盖了从类加载到类卸载的一系列过程:

  1. 加载(Loading):当 Java 虚拟机(JVM)需要使用某个类时,类加载器会根据类的全限定名(包名 + 类名)找到对应的.class字节码文件,并将其内容加载到 JVM 中。加载过程中,会在方法区中创建该类的相关数据结构,并在堆中创建一个java.lang.Class对象,作为对该类的访问入口。例如,当执行java HelloWorld命令运行程序时,JVM 会先加载HelloWorld类。
  2. 验证(Verification):确保加载进来的字节码文件符合 JVM 规范,保证其安全性和正确性。比如验证字节码文件格式是否正确、访问控制是否合理等,防止恶意代码或错误代码对 JVM 造成损害。
  3. 准备(Preparation):为类变量(使用static修饰的变量)分配内存并设置初始默认值,这些内存是在方法区中分配的。例如,对于public static int num = 10;,在准备阶段,num会被初始化为 0,而不是 10,10 的赋值操作是在初始化阶段完成。
  4. 解析(Resolution):将常量池中的符号引用转换为直接引用。符号引用是一种描述性的引用方式,比如使用类名、方法名等字符串来表示引用;直接引用则是指向目标的指针、句柄等。解析操作可以在类加载的初始化之前或之后进行,它主要针对类或接口、字段、类方法、接口方法等。
  5. 初始化(Initialization):真正执行类中定义的静态代码块、对类变量进行赋值操作等。JVM 会根据代码中定义的顺序,执行静态代码块和类变量的赋值语句。例如:

public class StaticInitialization {public static int num;static {num = 10;}
}

在初始化阶段,num会被赋值为 10 。
6. 使用(Using):类被加载、初始化完成后,就可以在程序中创建类的实例(对象),调用类的方法、访问类的属性等。比如HelloWorld类,在使用阶段就会执行main方法中的代码,输出Hello, World!
7. 卸载(Unloading):当类不再被引用,满足一定条件(如类的所有实例都被回收、加载该类的类加载器被回收等)时,JVM 会将类从内存中卸载,释放相关的内存资源。

Java 反射机制详解

反射(Reflection)是 Java 语言的一个重要特性,它允许程序在运行时获取类的信息并操作类或对象的属性、方法等成员。通过反射,我们可以在编译时未知类信息的情况下,动态地创建对象、调用方法和访问属性。

1. 反射的基本概念

反射机制允许程序:

  • 在运行时获取任意类的字节码信息
  • 在运行时构造任意类的对象
  • 在运行时调用任意类的方法
  • 在运行时访问和修改任意类的属性

反射的核心是java.lang.Class类,它代表了一个类的字节码,并提供了获取类信息的方法。

2. 获取 Class 对象的三种方式

获取Class对象是使用反射的第一步,有三种常用方式:

// 方式1:通过类名.class获取
Class<?> clazz1 = String.class;// 方式2:通过对象的getClass()方法获取
String str = "Hello";
Class<?> clazz2 = str.getClass();// 方式3:通过Class.forName()方法获取(最常用,可动态加载类)
Class<?> clazz3 = Class.forName("java.lang.String");

3. 反射常用类

Java 反射主要涉及以下类(均位于java.lang.reflect包):

  • Class:代表类的字节码
  • Constructor:代表类的构造方法
  • Method:代表类的方法
  • Field:代表类的成员变量
  • Parameter:代表方法的参数(Java 8+)

4. 反射的基本操作

4.1 创建对象

通过反射创建对象有两种方式:

public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}// getter、setter和toString方法省略
}

// 获取Class对象
Class<?> personClass = Class.forName("com.example.Person");// 方式1:通过无参构造方法创建对象(要求类必须有无参构造)
Person person1 = (Person) personClass.newInstance();// 方式2:通过指定构造方法创建对象
Constructor<?> constructor = personClass.getConstructor(String.class, int.class);
Person person2 = (Person) constructor.newInstance("Alice", 20);

4.2 获取和调用方法

// 获取所有公共方法(包括继承的)
Method[] methods = personClass.getMethods();// 获取类自身声明的所有方法(包括私有)
Method[] declaredMethods = personClass.getDeclaredMethods();// 获取指定公共方法
Method setNameMethod = personClass.getMethod("setName", String.class);// 获取指定私有方法
Method privateMethod = personClass.getDeclaredMethod("privateMethod");
// 设置访问权限(关键)
privateMethod.setAccessible(true);// 调用方法
Person person = new Person();
setNameMethod.invoke(person, "Bob");  // 调用public方法
privateMethod.invoke(person);         // 调用private方法

4.3 获取和操作属性

// 获取所有公共属性(包括继承的)
Field[] fields = personClass.getFields();// 获取类自身声明的所有属性(包括私有)
Field[] declaredFields = personClass.getDeclaredFields();// 获取指定公共属性
Field publicField = personClass.getField("publicField");// 获取指定私有属性
Field nameField = personClass.getDeclaredField("name");
// 设置访问权限
nameField.setAccessible(true);// 操作属性
Person person = new Person();
nameField.set(person, "Charlie");  // 设置私有属性值
String name = (String) nameField.get(person);  // 获取私有属性值

5. 反射的应用场景

  1. 框架开发:Spring、MyBatis 等框架大量使用反射实现对象创建和依赖注入
  2. 动态代理:AOP 实现的基础
  3. 序列化与反序列化:将对象转换为字节流或从字节流恢复对象
  4. 注解处理:通过反射获取注解信息并处理
  5. ORM 框架:实现对象与数据库表的映射

6. 反射示例:简易 ORM 框架

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;public class SimpleORM {// 保存对象到数据库public static void save(Object obj) throws Exception {Class<?> clazz = obj.getClass();StringBuilder sql = new StringBuilder("INSERT INTO ");sql.append(clazz.getSimpleName().toLowerCase()).append(" (");Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {sql.append(field.getName()).append(",");}// 移除最后一个逗号sql.deleteCharAt(sql.length() - 1);sql.append(") VALUES (");for (int i = 0; i < fields.length; i++) {sql.append("?,");}// 移除最后一个逗号sql.deleteCharAt(sql.length() - 1);sql.append(")");// 实际开发中需要获取数据库连接Connection conn = null; // 获取连接的代码省略PreparedStatement pstmt = conn.prepareStatement(sql.toString());for (int i = 0; i < fields.length; i++) {fields[i].setAccessible(true);pstmt.setObject(i + 1, fields[i].get(obj));}pstmt.executeUpdate();// 关闭资源的代码省略}
}

7. 反射的优缺点

优点

  • 提高程序灵活性和扩展性
  • 实现动态加载类和创建对象
  • 框架开发的基础

缺点

  • 性能开销较大:反射操作比直接调用慢
  • 破坏封装性:可以访问私有成员
  • 代码可读性降低:反射代码相对复杂
  • 安全问题:可能绕过安全检查

8. 反射性能优化

  1. 缓存 Class 对象:避免多次获取 Class 对象
  2. 设置 setAccessible (true):关闭安全检查,提高性能
  3. 使用 MethodHandle(Java 7+):比反射性能更好
  4. 避免在循环中使用反射:将反射操作移到循环外

// 缓存Method示例
public class ReflectionCache {private static Map<String, Method> methodCache = new HashMap<>();public static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {String key = clazz.getName() + "#" + methodName + Arrays.toString(parameterTypes);if (!methodCache.containsKey(key)) {Method method = clazz.getMethod(methodName, parameterTypes);method.setAccessible(true);methodCache.put(key, method);}return methodCache.get(key);}
}

9. 注意事项

  1. 反射会破坏封装,应谨慎使用
  2. 反射可能导致代码难以理解和维护
  3. 某些安全管理器可能会禁止反射操作
  4. 对于 final 字段,反射修改可能不会生效(取决于 JVM 实现)
  5. 使用反射时应处理各种可能的异常

总结

反射是 Java 中一个强大的特性,它允许程序在运行时操作类和对象的成员,为框架开发提供了极大的灵活性。然而,反射也有其缺点,如性能开销和封装性问题。在实际开发中,应根据具体需求权衡使用,并注意性能优化。

反射的核心是Class类,通过它可以获取类的各种信息,并借助ConstructorMethodField等类实现对类成员的操作。合理使用反射可以极大地提高代码的灵活性和扩展性。

整理成笔记,尽量详细

Java 反射实操笔记

一、反射核心 API 梳理

1.1 类对象获取方式

获取方式语法适用场景
Class.forName()Class clazz = Class.forName("全类名");编译时未知类,需动态加载(如读取配置文件)
类名.classClass clazz = 类名.class;编译时已知类,直接通过类名获取
对象.getClass()Class clazz = 对象名.getClass();已有对象实例,通过对象反推类信息

1.2 成员变量操作 API

1. 获取成员变量

  • getDeclaredFields():获取类中所有成员变量(包括 private、public、protected 修饰的)

    Field[] fields = pclass.getDeclaredFields();
    for(Field item : fields) {System.out.println(item);
    }
    
  • getDeclaredField(String name):获取指定名称的成员变量(包括私有)
    Field field_age = pclass.getDeclaredField("age");
    
  • getFields():仅获取类中 public 修饰的成员变量
    Field[] public_fields = pclass.getFields();
    

  • getField(String name):获取指定名称的 public 成员变量
    Field field_from = pclass.getField("from");
    

    • 设置成员变量值:field.set(Object obj, Object value)
    • 获取成员变量值:field.get(Object obj)
    • 访问私有成员变量:需要先调用 setAccessible(true) 取消访问检查

      // 设置 public 成员变量
      field_from.set(person, "中国");// 设置 private 成员变量
      field_age.setAccessible(true); // 关键:允许访问私有变量
      field_age.set(person, 20);// 获取成员变量值
      System.out.println(field_age.get(person));
      System.out.println(field_from.get(person));
      

方法访问权限范围功能描述
getDeclaredFields()类自身声明的所有成员变量(包括 private、protected、public)获取类的所有成员变量数组
getDeclaredField(String name)类自身声明的指定成员变量(任意权限)获取单个指定名称的成员变量
getFields()类及父类的 public 成员变量仅获取公共成员变量数组
getField(String name)类及父类的指定 public 成员变量获取单个指定名称的公共成员变量
set(Object obj, Object value)无(需配合setAccessible(true)给指定对象的成员变量赋值
get(Object obj)无(需配合setAccessible(true)获取指定对象的成员变量值
setAccessible(true)暴力解除访问权限检查让 private 成员变量可被操作(核心!)

1.3 成员方法操作 API

 获取方法

  • getDeclaredMethods():获取类中所有方法(包括私有)
    Method[] methods = pclass.getDeclaredMethods();
    
  • getDeclaredMethod(String name, Class<?>... parameterTypes):获取指定方法(包括私有)
    Method method_run = pclass.getDeclaredMethod("run");
    
  • getMethods():获取类中所有 public 方法(包括继承的)
    Method[] public_method = pclass.getMethods();
    
  • getMethod(String name, Class<?>... parameterTypes):获取指定的 public 方法
    Method method_get = pclass.getMethod("getAge");
    

2. 调用方法

  • 使用 method.invoke(Object obj, Object... args) 调用方法
  • 调用私有方法需先设置 setAccessible(true)
    // 调用 public 方法
    method_get.invoke(person);// 调用 private 方法
    method_run.setAccessible(true);
    method_run.invoke(person);
    

方法访问权限范围功能描述
getDeclaredMethods()类自身声明的所有方法(任意权限)获取类的所有方法数组
getDeclaredMethod(String name, Class<?>... paramTypes)类自身声明的指定方法(任意权限)获取单个指定名称 + 参数类型的方法
getMethods()类及父类的 public 方法仅获取公共方法数组(含 Object 类方法)
getMethod(String name, Class<?>... paramTypes)类及父类的指定 public 方法获取单个指定名称 + 参数类型的公共方法
invoke(Object obj, Object... args)无(需配合setAccessible(true)执行指定对象的方法,args 为方法参数
getName()获取方法的名称(字符串形式)
setAccessible(true)暴力解除访问权限检查让 private 方法可被调用

1.4 构造方法操作 API

. 获取构造器

  • getDeclaredConstructors():获取所有构造器(包括私有)
    Constructor[] constructors = pclass.getDeclaredConstructors();
    
  • getDeclaredConstructor(Class<?>... parameterTypes):获取指定构造器(包括私有)
    Constructor constructor = pclass.getDeclaredConstructor();
    Constructor constructor2 = pclass.getDeclaredConstructor(String.class, int.class);
    
  • getConstructors():获取所有 public 构造器
    Constructor[] public_constructors = pclass.getConstructors();
    
  • getConstructor(Class<?>... parameterTypes):获取指定的 public 构造器
    Constructor public_constructor = pclass.getConstructor();
    Constructor public_constructor2 = pclass.getConstructor(String.class);
    

2. 创建对象

  • 通过构造器的 newInstance(Object... initargs) 方法创建对象

    // 无参构造器创建对象
    Object object = constructor.newInstance();// 有参构造器创建对象
    Person object2 = (Person) constructor2.newInstance("lili", 20);
    

方法访问权限范围功能描述
getDeclaredConstructors()类自身声明的所有构造方法(任意权限)获取所有构造方法数组
getDeclaredConstructor(Class<?>... paramTypes)类自身声明的指定构造方法(任意权限)获取单个指定参数类型的构造方法(无参则传空)
getConstructors()类自身声明的 public 构造方法仅获取公共构造方法数组
getConstructor(Class<?>... paramTypes)类自身声明的指定 public 构造方法获取单个指定参数类型的公共构造方法
newInstance(Object... args)无(需配合setAccessible(true)通过构造方法创建对象实例,args 为构造参数

1.5 类信息获取 API

方法返回值功能描述
getName()String获取类的全名称(包名 + 类名,如com.qcby.reflect.Person
getSimpleName()String获取类的简单名称(仅类名,如Person

二、配置文件与核心类

2.1 配置文件:refconfig.properties

用于存储反射所需的类名和方法名,实现 “配置化加载”,避免硬编码。

# 全类名(包名+类名)
reflect.className=com.qcby.reflect.Person
# 要调用的方法名
reflect.methodName=getAge

2.2 目标类:Person.java

反射操作的目标类,包含不同权限的成员变量、方法和构造方法。

package com.qcby.reflect;public class Person {// 私有成员变量private String name;private int age;// 公共成员变量public String from;public String height;// 公共getter/setter(访问私有变量)public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {System.out.println("getAge方法执行");return age;}public void setAge(int age) {this.age = age;}// 私有方法private void run() {System.out.println("run方法执行");}// 构造方法(无参、1参、2参,均为public)public Person() {}public Person(String name) {this.name = name;}public Person(String name, int age) {this.name = name;this.age = age;}// 重写toString,便于打印对象信息@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + " , from = "+from+" , height = "+height+"]";}
}

三、反射实操案例

3.1 步骤 1:获取类对象

三种获取Person类对象的方式,文档 3 中均有演示:

// 方式1:通过Class.forName(推荐,支持动态加载)
Class pclass1 = Class.forName("com.qcby.reflect.Person");// 方式2:通过类名.class(编译时已知类)
Class pclass2 = Person.class;// 方式3:通过对象.getClass(已有对象实例)
Person person = new Person();
Class pclass3 = person.getClass();

3.2 步骤 2:操作成员变量

2.1 获取成员变量

// 1. 获取类自身所有成员变量(包括private)
Field[] allFields = pclass.getDeclaredFields();
for (Field item : allFields) {System.out.println(item); // 输出:private java.lang.String com.qcby.reflect.Person.name、private int com.qcby.reflect.Person.age 等
}// 2. 获取单个指定私有成员变量(如age)
Field ageField = pclass.getDeclaredField("age");
System.out.println(ageField); // 输出:private int com.qcby.reflect.Person.age// 3. 获取所有public成员变量(包括父类,此处父类为Object,无额外public变量)
Field[] publicFields = pclass.getFields();
for (Field item : publicFields) {System.out.println(item); // 输出:public java.lang.String com.qcby.reflect.Person.from、public java.lang.String com.qcby.reflect.Person.height
}// 4. 获取单个指定public成员变量(如from)
Field fromField = pclass.getField("from");
System.out.println(fromField); // 输出:public java.lang.String com.qcby.reflect.Person.from
2.2 赋值与取值

// 1. 给public变量赋值(直接操作,无需暴力反射)
Person person = new Person();
fromField.set(person, "中国"); // 给person的from变量赋值为“中国”// 2. 给private变量赋值(需先暴力解除权限)
ageField.setAccessible(true); // 关键:解除private权限检查
ageField.set(person, 20); // 给person的age变量赋值为20// 3. 获取变量值
System.out.println(ageField.get(person)); // 输出:20(获取private变量age的值)
System.out.println(fromField.get(person)); // 输出:中国(获取public变量from的值)
System.out.println(person); // 输出:Person [name=null, age=20 , from = 中国 , height = null](通过toString验证)

3.3 步骤 3:操作成员方法

3.1 获取成员方法

// 1. 获取类自身所有方法(包括private)
Method[] allMethods = pclass.getDeclaredMethods();
for (Method item : allMethods) {System.out.println(item); // 输出:private void com.qcby.reflect.Person.run()、public int com.qcby.reflect.Person.getAge() 等
}// 2. 获取单个指定private方法(如run,无参数)
Method runMethod = pclass.getDeclaredMethod("run");
System.out.println(runMethod); // 输出:private void com.qcby.reflect.Person.run()// 3. 获取所有public方法(含父类Object的方法,如toString、equals)
Method[] publicMethods = pclass.getMethods();
for (Method item : publicMethods) {System.out.println(item); // 输出:public int com.qcby.reflect.Person.getAge()、public java.lang.String com.qcby.reflect.Person.toString() 等System.out.println(item.getName()); // 输出方法名,如getAge、toString
}// 4. 获取单个指定public方法(如getAge,无参数)
Method getAgeMethod = pclass.getMethod("getAge");
System.out.println(getAgeMethod); // 输出:public int com.qcby.reflect.Person.getAge()
3.2 调用方法

Person person = new Person();
// 1. 调用public方法(直接调用)
getAgeMethod.invoke(person); // 输出:getAge方法执行(方法内部打印)// 2. 调用private方法(需先暴力解除权限)
runMethod.setAccessible(true); // 关键:解除private权限检查
runMethod.invoke(person); // 输出:run方法执行(方法内部打印)

3.4 步骤 4:操作构造方法

4.1 获取构造方法

// 1. 获取类自身所有构造方法(包括非public,此处Person构造均为public)
Constructor[] allConstructors = pclass.getDeclaredConstructors();
for (Constructor item : allConstructors) {System.out.println(item); // 输出:public com.qcby.reflect.Person()、public com.qcby.reflect.Person(java.lang.String)、public com.qcby.reflect.Person(java.lang.String,int)
}// 2. 获取单个指定构造方法(无参)
Constructor noArgConstructor = pclass.getDeclaredConstructor();
System.out.println(noArgConstructor); // 输出:public com.qcby.reflect.Person()// 3. 获取单个指定构造方法(2参:String + int)
Constructor twoArgConstructor = pclass.getDeclaredConstructor(String.class, int.class);
System.out.println(twoArgConstructor); // 输出:public com.qcby.reflect.Person(java.lang.String,int)// 4. 获取所有public构造方法(与getDeclaredConstructors()结果一致,因Person构造均为public)
Constructor[] publicConstructors = pclass.getConstructors();
for (Constructor item : publicConstructors) {System.out.println(item);
}// 5. 获取单个指定public构造方法(1参:String)
Constructor oneArgConstructor = pclass.getConstructor(String.class);
System.out.println(oneArgConstructor); // 输出:public com.qcby.reflect.Person(java.lang.String)
4.2 创建对象实例

// 1. 通过无参构造创建对象
Object person1 = noArgConstructor.newInstance();
System.out.println(person1); // 输出:Person [name=null, age=0 , from = null , height = null]// 2. 通过2参构造创建对象(需强转为Person类型)
Person person2 = (Person) twoArgConstructor.newInstance("lili", 20);
System.out.println(person2); // 输出:Person [name=lili, age=20 , from = null , height = null]
person2.getAge(); // 调用对象方法,输出:getAge方法执行

3.5 步骤 5:结合配置文件动态反射

通过Properties读取配置文件,动态获取类名和方法名,实现 “不修改代码,仅改配置即可切换反射目标”。

// 1. 创建Properties对象,用于读取配置文件
Properties properties = new Properties();// 2. 加载配置文件(通过类加载器获取输入流,路径为“包名/文件名”)
InputStream in = Person.class.getClassLoader().getResourceAsStream("com/qcby/reflect/refconfig.properties");
properties.load(in); // 加载配置文件内容// 3. 从配置文件中获取类名和方法名
String className = properties.getProperty("reflect.className"); // 取值:com.qcby.reflect.Person
String methodName = properties.getProperty("reflect.methodName"); // 取值:getAge// 4. 动态获取类对象
Class pclass = Class.forName(className);
System.out.println(pclass); // 输出:class com.qcby.reflect.Person// 5. 后续可继续动态操作(如获取方法、调用方法)
// 示例:获取所有成员变量
Field[] fields = pclass.getDeclaredFields();
for (Field item : fields) {System.out.println(item); // 输出Person的所有成员变量
}

四、关键注意事项

  1. setAccessible(true)的作用
    解除 Java 的访问权限检查,仅对getDeclaredXXX()获取的私有成员有效,getXXX()获取的公共成员无需此操作。
  2. 异常处理
    反射操作可能抛出ClassNotFoundException(类找不到)、NoSuchFieldException(字段找不到)、NoSuchMethodException(方法找不到)、IllegalAccessException(权限不足)等,需在方法上声明throws Exception或捕获处理。
  3. 类型强转
    通过newInstance()创建的对象默认是Object类型,需根据实际类强转为目标类型(如(Person) constructor.newInstance())。
  4. 性能问题
    反射操作比直接调用慢(需动态解析类信息),频繁操作时建议缓存ClassMethodField对象,减少重复获取。
http://www.dtcms.com/a/358956.html

相关文章:

  • 【软考架构】面向服务的体系结构(SOA)深度解析
  • 记IsaacSim中抓取物体的质量物理属性的影响
  • 【智能体】零代码学习 Coze 智能体(2)创建智能体的完整步骤
  • 直线与椭圆相交弦长计算公式
  • K8s服务日志收集方案文档
  • LeetCode 92. 反转链表 II - 算法解析
  • 微服务-ruoyi-cloud部署
  • 《动手学深度学习v2》学习笔记 | 2.3 线性代数
  • 吴恩达机器学习(三)
  • 第7.5节:awk语言 switch 语句
  • 【C++】掌握string类操作:高效处理字符串
  • k230 按键拍照后,将摄像头拍照的1920*1080分辨率的图片以jpg文件格式,保存到板载TF存储卡的指定文件夹目录中
  • MinerU本地化部署
  • Java的Optional实现优雅判空新体验【最佳实践】
  • 做一个实用的节假日工具
  • MQTT 连接建立与断开流程详解(一)
  • sunset: decoy靶场渗透
  • 20250830_Oracle 19c CDB+PDB(QMS)默认表空间、临时表空间、归档日志、闪回恢复区巡检手册
  • day42-Ansible
  • 动态规划--Day05--最大子数组和--53. 最大子数组和,2606. 找到最大开销的子字符串,1749. 任意子数组和的绝对值的最大值
  • 微信小程序开发教程(三)
  • java如何保证线程安全
  • RLPD——利用离线数据实现高效的在线RL:不进行离线RL预训练,直接应用离策略方法SAC,在线学习时对称采样离线数据
  • 【OpenGL】LearnOpenGL学习笔记17 - Cubemap、Skybox、环境映射(反射、折射)
  • 【pandas】.loc常用操作
  • 【SpringMVC】SSM框架【二】——SpringMVC超详细
  • 【运维篇第三弹】《万字带图详解分库分表》从概念到Mycat中间件使用再到Mycat分片规则,详解分库分表,有使用案例
  • DAEDAL:动态调整生成长度,让大语言模型推理效率提升30%的新方法
  • 基于SpringBoot的电脑商城系统【2026最新】
  • 漫谈《数字图像处理》之分水岭分割