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

JVM类加载系统详解:深入理解Java类的生命周期

🔄 JVM类加载系统详解:深入理解Java类的生命周期

📋 目录

  • 🔧 类加载机制
    • 🔄 类加载的生命周期
    • 📂 类加载器分类
    • 👨‍👩‍👧‍👦 双亲委派模型原理与作用
  • 🛠️ 自定义类加载器
    • 📝 自定义类加载器的实现步骤
    • 💥 打破双亲委派模型的场景与案例
  • 📊 性能优化与最佳实践
  • 🎯 总结

🔧 类加载机制

类加载机制是JVM的核心功能之一,它负责将Java类文件加载到内存中并转换为可执行的字节码。理解类加载机制对于Java开发者来说至关重要。

🔄 类加载的生命周期

类加载的完整生命周期包含七个阶段,每个阶段都有其特定的职责:

在这里插入图片描述

1. 📁 加载(Loading)

加载阶段是类加载过程的第一步,主要完成以下三件事:

  • 通过类的全限定名获取定义此类的二进制字节流
  • 将字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在内存中生成一个代表这个类的java.lang.Class对象
// 示例:类加载触发时机
public class ClassLoadingExample {public static void main(String[] args) {// 1. 首次主动使用时触发加载MyClass obj = new MyClass();// 2. 访问静态变量时触发加载System.out.println(MyClass.STATIC_FIELD);// 3. 调用静态方法时触发加载MyClass.staticMethod();// 4. 反射调用时触发加载try {Class.forName("com.example.MyClass");} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
2. 🔍 验证(Verification)

验证阶段确保Class文件的字节流中包含的信息符合当前虚拟机的要求:

验证类型验证内容目的
🔧 文件格式验证魔数、版本号、常量池确保输入的字节流能正确解析
🏗️ 元数据验证语义分析、继承关系确保不存在不符合Java语言规范的元数据信息
📝 字节码验证数据流分析、控制流分析确保程序语义是合法的、符合逻辑的
🔗 符号引用验证符号引用转换为直接引用确保解析动作能正确执行
3. 🛠️ 准备(Preparation)

准备阶段为类变量分配内存并设置类变量初始值:

public class PreparationExample {// 准备阶段:value = 0(零值)// 初始化阶段:value = 123(真正的初始值)public static int value = 123;// 准备阶段:finalValue = 456(编译期常量)public static final int finalValue = 456;// 准备阶段:obj = null(引用类型零值)public static Object obj = new Object();
}
4. 🔗 解析(Resolution)

解析阶段将常量池内的符号引用替换为直接引用:

// 符号引用示例
public class ResolutionExample {private AnotherClass another; // 符号引用:AnotherClasspublic void method() {// 方法调用的符号引用another.someMethod(); // 符号引用:someMethod}
}class AnotherClass {public void someMethod() {System.out.println("Method called");}
}
5. ⚡ 初始化(Initialization)

初始化阶段执行类构造器<clinit>()方法:

public class InitializationExample {static {System.out.println("静态代码块执行");}private static int count = getInitialCount();private static int getInitialCount() {System.out.println("静态方法执行");return 10;}// 输出顺序:// 1. 静态代码块执行// 2. 静态方法执行
}

📂 类加载器分类

JVM中的类加载器形成了一个层次化的结构:

graph TDA[🚀 Bootstrap ClassLoader<br/>启动类加载器] --> B[🔧 Extension ClassLoader<br/>扩展类加载器]B --> C[📱 Application ClassLoader<br/>应用程序类加载器]C --> D[🛠️ Custom ClassLoader<br/>自定义类加载器]A1["📚 加载核心类库<br/>$JAVA_HOME/lib"] --> AB1["🔌 加载扩展类库<br/>$JAVA_HOME/lib/ext"] --> BC1["📦 加载应用程序类<br/>ClassPath"] --> CD1["🎯 特定需求加载<br/>网络、数据库等"] --> Dstyle A fill:#ff6b6bstyle B fill:#4ecdc4style C fill:#45b7d1style D fill:#96ceb4
🚀 启动类加载器(Bootstrap ClassLoader)
// 查看启动类加载器加载的类
public class BootstrapClassLoaderExample {public static void main(String[] args) {// String类由启动类加载器加载System.out.println("String类加载器: " + String.class.getClassLoader());// 输出:null(表示启动类加载器)// 查看启动类加载器的搜索路径System.out.println("启动类加载器路径: " + System.getProperty("sun.boot.class.path"));}
}
🔧 扩展类加载器(Extension ClassLoader)
// 查看扩展类加载器
public class ExtensionClassLoaderExample {public static void main(String[] args) {// 获取扩展类加载器ClassLoader extClassLoader = ClassLoader.getSystemClassLoader().getParent();System.out.println("扩展类加载器: " + extClassLoader);// 查看扩展类加载器的搜索路径System.out.println("扩展类路径: " + System.getProperty("java.ext.dirs"));}
}
📱 应用程序类加载器(Application ClassLoader)
// 应用程序类加载器示例
public class ApplicationClassLoaderExample {public static void main(String[] args) {// 获取应用程序类加载器ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();System.out.println("应用程序类加载器: " + appClassLoader);// 查看当前类的加载器System.out.println("当前类加载器: " + ApplicationClassLoaderExample.class.getClassLoader());// 查看类路径System.out.println("类路径: " + System.getProperty("java.class.path"));}
}

👨‍👩‍👧‍👦 双亲委派模型原理与作用

双亲委派模型是Java类加载器的核心机制,它确保了Java核心API的安全性和一致性。

🔄 工作原理
应用程序类加载器 扩展类加载器 启动类加载器 1. 委派给父加载器 2. 继续向上委派 3. 尝试加载类 4a. 返回Class对象 5a. 返回Class对象 4b. 返回null 5b. 自己尝试加载 6a. 返回Class对象 6b. 返回null 7. 自己尝试加载 alt [扩展类加载器- 能加载] [扩展类加载器- 无法加载] alt [启动类加载器能加载] [启动类加载器无法加载] 应用程序类加载器 扩展类加载器 启动类加载器
💻 源码实现
// ClassLoader.loadClass()方法的核心逻辑
protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// 1. 检查类是否已经被加载Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {// 2. 委派给父加载器if (parent != null) {c = parent.loadClass(name, false);} else {// 3. 父加载器为null,委派给启动类加载器c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// 父加载器无法加载,继续执行}if (c == null) {// 4. 父加载器无法加载,自己尝试加载long t1 = System.nanoTime();c = findClass(name);// 记录统计信息sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}
}
🛡️ 双亲委派模型的作用
作用说明示例
🔒 安全性防止核心API被篡改无法自定义java.lang.String类
🎯 一致性确保类的唯一性同一个类只会被加载一次
📦 避免重复防止类的重复加载父加载器已加载的类不会重复加载
🏗️ 层次化管理清晰的加载器层次结构核心类库 → 扩展类库 → 应用类库
// 双亲委派模型安全性示例
public class SecurityExample {public static void main(String[] args) {try {// 尝试加载自定义的String类(会失败)Class<?> stringClass = Class.forName("java.lang.String");System.out.println("String类加载器: " + stringClass.getClassLoader());// 输出:null(由启动类加载器加载,不是自定义的)} catch (ClassNotFoundException e) {e.printStackTrace();}}
}// 即使创建了这个类,也不会被加载
package java.lang;
public class String {// 这个类永远不会被加载,因为双亲委派模型// 会优先使用启动类加载器中的java.lang.String
}

🛠️ 自定义类加载器

在某些特殊场景下,我们需要自定义类加载器来满足特定的需求,比如从网络加载类、加密类文件、热部署等。

📝 自定义类加载器的实现步骤

步骤1:继承ClassLoader类
public class CustomClassLoader extends ClassLoader {private String classPath;public CustomClassLoader(String classPath) {this.classPath = classPath;}public CustomClassLoader(String classPath, ClassLoader parent) {super(parent);this.classPath = classPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {// 获取类文件的字节数组byte[] classData = loadClassData(name);if (classData == null) {throw new ClassNotFoundException("Class " + name + " not found");}// 将字节数组转换为Class对象return defineClass(name, classData, 0, classData.length);} catch (Exception e) {throw new ClassNotFoundException("Error loading class " + name, e);}}private byte[] loadClassData(String className) {try {// 将类名转换为文件路径String fileName = classPath + File.separator + className.replace('.', File.separatorChar) + ".class";// 读取类文件FileInputStream fis = new FileInputStream(fileName);ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int length;while ((length = fis.read(buffer)) != -1) {baos.write(buffer, 0, length);}fis.close();return baos.toByteArray();} catch (IOException e) {e.printStackTrace();return null;}}
}
步骤2:网络类加载器示例
public class NetworkClassLoader extends ClassLoader {private String baseUrl;public NetworkClassLoader(String baseUrl) {this.baseUrl = baseUrl;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] classData = loadClassFromNetwork(name);return defineClass(name, classData, 0, classData.length);} catch (Exception e) {throw new ClassNotFoundException("Failed to load class from network: " + name, e);}}private byte[] loadClassFromNetwork(String className) throws IOException {String classUrl = baseUrl + "/" + className.replace('.', '/') + ".class";URL url = new URL(classUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");try (InputStream is = connection.getInputStream();ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int length;while ((length = is.read(buffer)) != -1) {baos.write(buffer, 0, length);}return baos.toByteArray();}}
}
步骤3:加密类加载器示例
public class EncryptedClassLoader extends ClassLoader {private String classPath;private String key;public EncryptedClassLoader(String classPath, String key) {this.classPath = classPath;this.key = key;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] encryptedData = loadEncryptedClassData(name);byte[] decryptedData = decrypt(encryptedData, key);return defineClass(name, decryptedData, 0, decryptedData.length);} catch (Exception e) {throw new ClassNotFoundException("Failed to load encrypted class: " + name, e);}}private byte[] loadEncryptedClassData(String className) throws IOException {String fileName = classPath + File.separator + className.replace('.', File.separatorChar) + ".encrypted";try (FileInputStream fis = new FileInputStream(fileName);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int length;while ((length = fis.read(buffer)) != -1) {baos.write(buffer, 0, length);}return baos.toByteArray();}}private byte[] decrypt(byte[] encryptedData, String key) {// 简单的XOR解密示例byte[] keyBytes = key.getBytes();byte[] decryptedData = new byte[encryptedData.length];for (int i = 0; i < encryptedData.length; i++) {decryptedData[i] = (byte) (encryptedData[i] ^ keyBytes[i % keyBytes.length]);}return decryptedData;}
}
步骤4:使用自定义类加载器
public class CustomClassLoaderTest {public static void main(String[] args) {try {// 1. 使用自定义文件类加载器CustomClassLoader fileLoader = new CustomClassLoader("/path/to/classes");Class<?> clazz1 = fileLoader.loadClass("com.example.TestClass");Object instance1 = clazz1.newInstance();// 2. 使用网络类加载器NetworkClassLoader networkLoader = new NetworkClassLoader("http://example.com/classes");Class<?> clazz2 = networkLoader.loadClass("com.example.RemoteClass");Object instance2 = clazz2.newInstance();// 3. 使用加密类加载器EncryptedClassLoader encryptedLoader = new EncryptedClassLoader("/path/to/encrypted", "mySecretKey");Class<?> clazz3 = encryptedLoader.loadClass("com.example.SecretClass");Object instance3 = clazz3.newInstance();// 验证类加载器System.out.println("Class1 loader: " + clazz1.getClassLoader());System.out.println("Class2 loader: " + clazz2.getClassLoader());System.out.println("Class3 loader: " + clazz3.getClassLoader());} catch (Exception e) {e.printStackTrace();}}
}

💥 打破双亲委派模型的场景与案例

虽然双亲委派模型是推荐的做法,但在某些特殊场景下需要打破这个模型:

🔥 场景1:热部署(Hot Deployment)
public class HotDeployClassLoader extends ClassLoader {private String classPath;private Set<String> loadedClasses = new HashSet<>();public HotDeployClassLoader(String classPath) {super(null); // 不设置父加载器,打破双亲委派this.classPath = classPath;}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 对于系统类,仍然委派给系统类加载器if (name.startsWith("java.") || name.startsWith("javax.")) {return getSystemClassLoader().loadClass(name);}// 对于应用类,直接自己加载(打破双亲委派)return findClass(name);}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] classData = loadClassData(name);loadedClasses.add(name);return defineClass(name, classData, 0, classData.length);} catch (Exception e) {throw new ClassNotFoundException("Class not found: " + name, e);}}// 重新加载指定类public Class<?> reloadClass(String name) throws ClassNotFoundException {// 创建新的类加载器实例HotDeployClassLoader newLoader = new HotDeployClassLoader(this.classPath);return newLoader.loadClass(name);}private byte[] loadClassData(String className) throws IOException {String fileName = classPath + File.separator + className.replace('.', File.separatorChar) + ".class";try (FileInputStream fis = new FileInputStream(fileName);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int length;while ((length = fis.read(buffer)) != -1) {baos.write(buffer, 0, length);}return baos.toByteArray();}}
}
🌐 场景2:OSGi框架

OSGi(Open Service Gateway Initiative)是一个动态模块化系统,它完全打破了双亲委派模型:

// OSGi风格的类加载器(简化版)
public class OSGiClassLoader extends ClassLoader {private Bundle bundle;private Map<String, ClassLoader> importedPackages;public OSGiClassLoader(Bundle bundle) {super(null); // 不设置父加载器this.bundle = bundle;this.importedPackages = new HashMap<>();}@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {// 1. 检查是否已经加载Class<?> clazz = findLoadedClass(name);if (clazz != null) {return clazz;}// 2. 检查是否是系统类if (isSystemClass(name)) {return getSystemClassLoader().loadClass(name);}// 3. 检查是否是导入的包String packageName = getPackageName(name);ClassLoader importedLoader = importedPackages.get(packageName);if (importedLoader != null) {return importedLoader.loadClass(name);}// 4. 尝试从当前bundle加载try {return findClass(name);} catch (ClassNotFoundException e) {// 5. 委派给其他bundle(动态查找)return loadFromOtherBundles(name);}}private boolean isSystemClass(String name) {return name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("org.osgi.");}private String getPackageName(String className) {int lastDot = className.lastIndexOf('.');return lastDot > 0 ? className.substring(0, lastDot) : "";}private Class<?> loadFromOtherBundles(String name) throws ClassNotFoundException {// 在OSGi框架中查找能够提供该类的其他bundle// 这里是简化实现throw new ClassNotFoundException("Class not found in any bundle: " + name);}
}
🔧 场景3:Tomcat的类加载机制

Tomcat为了实现应用隔离,采用了复杂的类加载器层次结构:

Bootstrap ClassLoader
System ClassLoader
Common ClassLoader
Catalina ClassLoader
Shared ClassLoader
WebApp ClassLoader 1
WebApp ClassLoader 2
WebApp ClassLoader N
// Tomcat WebApp类加载器(简化版)
public class WebAppClassLoader extends ClassLoader {private String webAppPath;private ClassLoader commonLoader;private boolean delegate = false;public WebAppClassLoader(String webAppPath, ClassLoader commonLoader) {super(commonLoader);this.webAppPath = webAppPath;this.commonLoader = commonLoader;}@Overridepublic Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {Class<?> clazz = null;// 1. 检查是否已经加载clazz = findLoadedClass(name);if (clazz != null) {if (resolve) resolveClass(clazz);return clazz;}// 2. 检查是否是系统类if (isSystemClass(name)) {try {clazz = getSystemClassLoader().loadClass(name);if (clazz != null) {if (resolve) resolveClass(clazz);return clazz;}} catch (ClassNotFoundException e) {// 继续处理}}// 3. 根据delegate标志决定是否先委派给父加载器if (delegate) {try {clazz = commonLoader.loadClass(name);if (clazz != null) {if (resolve) resolveClass(clazz);return clazz;}} catch (ClassNotFoundException e) {// 继续处理}}// 4. 尝试从WebApp目录加载try {clazz = findClass(name);if (clazz != null) {if (resolve) resolveClass(clazz);return clazz;}} catch (ClassNotFoundException e) {// 继续处理}// 5. 如果没有设置delegate,现在委派给父加载器if (!delegate) {try {clazz = commonLoader.loadClass(name);if (clazz != null) {if (resolve) resolveClass(clazz);return clazz;}} catch (ClassNotFoundException e) {// 继续处理}}throw new ClassNotFoundException(name);}private boolean isSystemClass(String name) {return name.startsWith("java.") || name.startsWith("javax.");}
}
📊 打破双亲委派模型的对比
场景原因实现方式优点缺点
🔥 热部署需要重新加载类创建新的类加载器支持动态更新内存占用增加
🌐 OSGi模块化隔离复杂的委派网络模块独立性强复杂度高
🔧 TomcatWeb应用隔离先自己加载再委派应用间隔离可能导致类冲突
🎯 SPI机制核心类调用实现类线程上下文类加载器解决反向依赖破坏了模型一致性

📊 性能优化与最佳实践

⚡ 类加载性能优化

1. 🚀 预加载关键类
public class ClassPreloader {private static final String[] CRITICAL_CLASSES = {"com.example.core.Service","com.example.util.Helper","com.example.config.Configuration"};public static void preloadCriticalClasses() {long startTime = System.currentTimeMillis();for (String className : CRITICAL_CLASSES) {try {Class.forName(className);System.out.println("Preloaded: " + className);} catch (ClassNotFoundException e) {System.err.println("Failed to preload: " + className);}}long endTime = System.currentTimeMillis();System.out.println("Preloading completed in " + (endTime - startTime) + "ms");}
}
2. 📈 类加载监控
public class ClassLoadingMonitor {private static final Map<String, Long> loadingTimes = new ConcurrentHashMap<>();private static final AtomicLong totalLoadingTime = new AtomicLong(0);private static final AtomicInteger classCount = new AtomicInteger(0);public static void recordClassLoading(String className, long loadTime) {loadingTimes.put(className, loadTime);totalLoadingTime.addAndGet(loadTime);classCount.incrementAndGet();}public static void printStatistics() {System.out.println("=== 类加载统计 ===");System.out.println("总加载类数: " + classCount.get());System.out.println("总加载时间: " + totalLoadingTime.get() + "ms");System.out.println("平均加载时间: " + (totalLoadingTime.get() / Math.max(1, classCount.get())) + "ms");// 找出加载时间最长的类loadingTimes.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).limit(10).forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue() + "ms"));}
}
3. 🎯 最佳实践
// 最佳实践示例
public class ClassLoadingBestPractices {// ✅ 好的做法:延迟加载private static class LazyHolder {private static final ExpensiveResource INSTANCE = new ExpensiveResource();}public static ExpensiveResource getInstance() {return LazyHolder.INSTANCE; // 只有在首次调用时才加载}// ✅ 好的做法:缓存Class对象private static final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();public static Class<?> loadClassWithCache(String className) throws ClassNotFoundException {return classCache.computeIfAbsent(className, name -> {try {return Class.forName(name);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}});}// ✅ 好的做法:避免不必要的类加载public static boolean isClassAvailable(String className) {try {Class.forName(className);return true;} catch (ClassNotFoundException e) {return false;}}// ❌ 避免的做法:频繁的反射调用public void badPractice() {for (int i = 0; i < 1000; i++) {try {Class.forName("com.example.SomeClass"); // 每次都重新加载} catch (ClassNotFoundException e) {e.printStackTrace();}}}// ✅ 改进的做法:一次加载,多次使用private static final Class<?> SOME_CLASS;static {try {SOME_CLASS = Class.forName("com.example.SomeClass");} catch (ClassNotFoundException e) {throw new RuntimeException("Failed to load SomeClass", e);}}public void goodPractice() {for (int i = 0; i < 1000; i++) {// 使用已加载的Class对象Object instance = SOME_CLASS.newInstance();}}
}

🔧 JVM参数优化

# 类加载相关的JVM参数
-XX:+TraceClassLoading          # 跟踪类加载过程
-XX:+TraceClassUnloading        # 跟踪类卸载过程
-XX:+PrintGCDetails             # 打印GC详细信息(包括类卸载)
-XX:MetaspaceSize=256m          # 设置Metaspace初始大小
-XX:MaxMetaspaceSize=512m       # 设置Metaspace最大大小
-XX:+UseCompressedOops          # 启用压缩指针(减少内存占用)
-XX:+UseCompressedClassPointers # 启用压缩类指针

🎯 总结

通过本文的深入分析,我们全面了解了JVM类加载系统的核心机制:

🔑 关键要点

方面核心内容实际应用
🔄 类加载生命周期7个阶段的详细过程理解类初始化时机,避免循环依赖
📂 类加载器层次三层类加载器结构合理设计类路径,避免类冲突
👨‍👩‍👧‍👦 双亲委派模型安全性和一致性保证理解类加载顺序,设计安全的应用
🛠️ 自定义类加载器特殊场景的解决方案实现热部署、插件系统、加密加载
💥 打破双亲委派特殊框架的实现原理理解OSGi、Tomcat等框架设计

🚀 实践建议

  1. 🎯 合理使用类加载机制

    • 利用延迟加载提高启动性能
    • 缓存Class对象避免重复加载
    • 监控类加载性能找出瓶颈
  2. 🔒 注意安全性问题

    • 理解双亲委派模型的安全作用
    • 谨慎打破双亲委派模型
    • 验证自定义类加载器的安全性
  3. ⚡ 性能优化策略

    • 预加载关键类减少首次访问延迟
    • 合理设置Metaspace大小
    • 使用类加载监控工具分析性能

🔮 进阶学习方向

  • 🌐 模块化系统:深入学习Java 9+的模块系统
  • 🔥 热部署技术:研究JRebel、Spring DevTools等工具
  • 🏗️ 框架源码:分析Spring、Tomcat等框架的类加载实现
  • 🛡️ 安全机制:学习Java安全管理器和代码签名

💡 提示:类加载系统是JVM的核心组件之一,深入理解它有助于我们更好地设计和优化Java应用程序。在实际开发中,要根据具体需求选择合适的类加载策略,既要保证功能实现,也要考虑性能和安全性。


如果这篇文章对您有帮助,欢迎点赞、评论和分享。感谢您的阅读!


文章转载自:
http://belize.wanhuigw.com
http://alevin.wanhuigw.com
http://arytenoid.wanhuigw.com
http://biaxial.wanhuigw.com
http://capeador.wanhuigw.com
http://biosystematics.wanhuigw.com
http://batteries.wanhuigw.com
http://cheero.wanhuigw.com
http://arcover.wanhuigw.com
http://cartoonist.wanhuigw.com
http://cautelous.wanhuigw.com
http://antibiotic.wanhuigw.com
http://anvers.wanhuigw.com
http://baddeleyite.wanhuigw.com
http://breadline.wanhuigw.com
http://besmirch.wanhuigw.com
http://archenemy.wanhuigw.com
http://beanball.wanhuigw.com
http://artel.wanhuigw.com
http://britska.wanhuigw.com
http://capitulum.wanhuigw.com
http://assizes.wanhuigw.com
http://bearberry.wanhuigw.com
http://carport.wanhuigw.com
http://acculturate.wanhuigw.com
http://aardvark.wanhuigw.com
http://biblical.wanhuigw.com
http://bairn.wanhuigw.com
http://bootlast.wanhuigw.com
http://avocation.wanhuigw.com
http://www.dtcms.com/a/266227.html

相关文章:

  • 数字资产革命中的信任之锚:RWA法律架构的隐形密码
  • 基于Linux的Spark本地模式环境搭建实验指南
  • 白色氧化铈:“白”光之下的科技之美
  • 衡石科技破解指标管理技术难题:语义层建模如何实现业务与技术语言对齐?
  • 【C#】命名空间
  • 尝试安装使用无头cms strapi (未完成)
  • 【数据结构】时间复杂度与空间复杂度
  • 【C++】访问者模式中的双重分派机制详解
  • 淋巴细胞激活靶点CD6
  • 【人工智能与机器人研究】优化YOLOv11模型:基于多尺度注意力机制的小目标检测性能提升研究
  • RRF (Reciprocal Rank Fusion) 排序算法详解
  • 【排序算法】
  • Vue3封装动态Form表单
  • 第二章-AIGC入门-开启AIGC音频探索之旅:从入门到实践(6/36)
  • 【学术写作+AI实战】株洲高校科研写作研修班全纪实:核心期刊编辑与AI专家的联合授课笔记
  • Web前端数据可视化:ECharts高效数据展示完全指南
  • 【JavaEE】计算机工作原理
  • JavaEE初阶第七期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(五)
  • 运维打铁:企业云服务解决方案
  • openEuler 24.03 全流程实战:用 Ansible 5 分钟部署分布式 MinIO 高可用集群
  • Django+DRF 实战:从异常捕获到自定义错误信息
  • 深度分析:Microsoft .NET Framework System.Random 的 C++ 复刻实现
  • 切出idea窗口自动编译,关闭idea自动编译
  • WPF+HelixToolkit打造炫酷自定义3D贴图立方体盒子模型
  • 机器学习在智能供应链中的应用:需求预测与物流优化
  • Java技术深潜:从并发陷阱到云原生突围
  • web网页,在线%电商,茶叶,商城,网上商城系统%分析系统demo,于vscode,vue,java,jdk,springboot,mysql数据库
  • 警惕 Rust 字符串的性能陷阱:`chars().nth()` 的深坑与高效之道
  • 「AI产业」| 《中国信通院华为:智能体技术和应用研究报告》
  • P1202 [USACO1.1] 黑色星期五Friday the Thirteenth