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

【JVM系列】- 类加载子系统与加载过程

类加载子系统与加载过程

😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页   @怒放吧德德  To记录领地
🌝分享学习心得,欢迎指正,大家一起学习成长!

在这里插入图片描述

文章目录

  • 类加载子系统与加载过程
    • 内存结构简介
    • 类的加载过程
      • 1) 加载(Loading)
      • 2) 链接(Linking)
        • ① 验证(Verification)
        • ② 准备(Preparation)
        • ③ 解析(Resolution)
      • 3) *初始化(Initialization)
        • 何时促发初始化:
        • \<init>()与\<clinit>()
    • 类的加载器
      • 1) 三个核心类加载器
      • 2) 自定义类加载器
        • 为什么要自定义加载类
        • 如何自定义类加载器
      • 3) 双亲委派机制
        • ① 双亲委派的原理
        • ② 双亲委派机制优势
        • ③ 沙箱安全机制
        • ④ 破坏双亲委派机制
    • 总结
    • 博客文献

内存结构简介

Java虚拟机会通过类加载器子系统去加载字节码,在类加载的过程还包括了将字节码文件加载到内存,JVM会验证字节码文件的格式、解析符号引用,初始化类、接口等,为静态字段分配内存并初始化。会在内存中创建相应的对象,以及对一些静态变量进行初始化等操作,这部分主要是在方法区中执行。然而真正执行字节码指令的是执行引擎,他会根据字节码的顺序去执行,这也就涉及了计数器、栈等的操作。
在这里插入图片描述

类的加载过程

类加载器包括了加载、链接、初始化三个阶段,每个阶段都有各自的处理行为。

类加载器(Class Loader)是Java虚拟机(JVM)的一个关键组件,它负责将类文件加载到内存中,以便在程序中使用。类加载器的主要任务是在运行时查找并加载类文件,然后生成类的字节码以供JVM执行。类加载器的主要功能包括加载、链接和初始化类。

未命名文件 (3).png
类的加载流程如下:
1) 加载(Loading): 类加载器查找类文件,通常是.class文件,然后将它们加载到内存中。加载过程包括查找类文件、读取类文件的字节码数据,并创建一个表示类的java.lang.Class对象。
2) 链接(Linking): 链接分为三个阶段:验证、准备和解析。
① 验证(Verification): 在这个阶段,类加载器确保类文件的字节码是合法、符合规范的,并且不包含危险的构造。这是为了确保安全性。
② 准备(Preparation): 在这个阶段,类的静态变量分配内存并初始化为默认值。
③ 解析(Resolution): 这个阶段负责将符号引用解析为直接引用,以便JVM能够识别和访问其他类和方法。
3) 初始化(Initialization): 在这个阶段,类的静态初始化块(static initializer)被执行,静态变量被赋予初始值。这是类加载的最后一个阶段。
*类加载器子系统只是负责加载字节码文件,至于它能否运行,还是得由执行引擎来决定。加载类信息包括类的结构信息、运行时常量池、父类信息并且建立继承和接口实现关系。

需要注意的是,在Java 8之前,这些信息存储在方法区中,而在Java 8及以后,方法区被替代为元数据区(Metaspace),并且元数据区采用了一种不同的内存管理方式,它会根据需要动态分配和回收内存,而不是采用固定的区域大小。

1) 加载(Loading)

加载时类加载过程的第一个阶段,在加载阶段,Java虚拟机需要完成以下三件事情:

  • 通过一个类的全限定名来获取其定义的二进制字节流。
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口

未命名文件 (4).png
这个类加载就是加载二进制字节流的动作,开发者不仅可以使用系统提供的加载器加载,也可以是自己自定义一个类加载器,在自己自定义的类加载器中去做一些其他的操作。
类加载会将class文件的结构、方法、字段、注解、访问权限等信息加载到方法区/元数据区中,堆中会用于存储对象实例的内存区域。

类的加载方式

  • 从本地系统中直接加载
  • 通过网络下载.class文件
  • 从zip,jar等归档文件中加载.class文件
  • 从专有数据库中提取.class文件
  • 将Java源文件动态编译为.class文件

2) 链接(Linking)

链接阶段又分为三个阶段,分别是验证、准备、解析。目的是为了确保类的结构和引用在运行时是有效的和安全的。通过验证、准备和解析,JVM可以在类加载时会进行必要的检查和调整,以防止潜在的安全问题和运行时错误。这有助于维护Java程序的稳定性和安全性。在链接阶段中,类变量(静态变量)会被分配默认值。对于基本数据类型,这个默认值通常是0或0.0。对于对象引用类型,这个默认值是null。

① 验证(Verification)

在验证阶段,类加载器需要确保类文件的字节码是否合法、符合规范的,并且不会造成危险。简单来说就是确保被加载类的正确性。

验证的方式:

  • 格式验证:检查字节码文件的格式是否正确。
  • 语义验证:检查字节码文件中的操作是否符合Java语言规范。
  • 字节码验证:检查字节码文件中的操作是否与类的结构和继承关系一致。
  • 符号引用验证:检查符号引用是否有效,不引用不存在的类或字段。

类加载的字节码文件,字节流数据是以0xCAFEBABE开头。这是一种规范,能够来验证字节码文件是否符合Java规范。
这里我们可以看一下编译后的Java字节码的二进制数据长什么样。我们可以在idea中安装一个插件【BinEd-binary-hexadecimal-editor】,然后我们找到编译后的Java字节码文件,然后右键->open in->Binary Editor;就可以在界面上看到十六进制/二进制与代码的对应。
在这里插入图片描述

从图中我们就能看到0xCAFEBABE这段十六进制数值。

② 准备(Preparation)
  • 准备阶段主要是用于为类的静态字段分配内存并初始化这些字段。这些字段将在类初始化阶段(Initialization)中赋予实际的初始值。

当我们在类中定义了一个变量public static int a = 1;此时在准备阶段的时候,这个值是0,并不是1,直到初始化阶段的时候才会被赋值为1。

  • 但是这里不包含使用final修饰的static,因为final修饰的变量在编译的时候就会分配好内存,准备阶段会显式初始化。如果final修饰的变量进行赋值,此时会直接报错。

在准备阶段,常量字段(public static final修饰的字段被视为常量)会被分配内存并赋予初始值。对于public static final int c = 3; 这个常量字段,它的初始值将被设置为3。这是因为public static final字段被认为是编译时常量,其值在编译时已经确定。

  • 这里不会为实例变量分配初始化,类变量会分配到方法区中,而实例变量是会随着对象一起分配到Java堆中。
③ 解析(Resolution)
  • 解析阶段负责将符号引用解析为直接引用,以便JVM能够识别和访问其他类和方法。
  • 符号引用是一种符号化的引用,它以符号的方式描述了类、字段、方法或接口的引用,而不包括直接的内存地址或偏移量。直接引用是实际的内存地址或偏移量,它用于直接定位并访问类的实例、字段、方法或接口。
  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

3) *初始化(Initialization)

初始化阶段(Initialization)是初始化过程的关键步骤。在这个阶段,类的静态初始化块(static initializer)会被执行,用于为静态字段分配实际的初始值。静态初始化块可以包含任意Java代码,通常用于执行一些静态设置操作。需要注意的是,初始化是懒加载的,即只有在首次触发初始化时才会执行。一旦类被成功初始化,它不会再次初始化,除非应用程序中的某些特殊情况强制重新初始化类。

何时促发初始化:
  • 创建类的实例:当创建类的实例时,首先要确保类已经被初始化。
  • 访问类的静态字段或静态方法:访问静态成员时,会触发类的初始化。
  • 使用反射操作:通过反射方式访问类时,也会触发初始化。
<init>()与<clinit>()

首先我们需要了解一下<init>()与<clinit>()这两个Java编译自动生成的方法。
方法: 这是类的构造方法,用于对象的初始化。构造方法的名称是,它包括在类的字节码中以执行对象初始化操作。不同的构造方法可以接受不同的参数,用于初始化对象的各个属性。
首先我们通过一个例子来了解一下Java 的方法,以下编写了一段两个变量的Java代码,a是成员变量,b、c是局部变量,通过构造方法来对a进行赋值。我们在idea安装 jclasslib-bytecode-viewer 插件,可以通过这个插件来查看Java字节码。

public class JVM01 {private int a = 1;public JVM01() {a = 10;}public static void main(String[] args) {int b = 3;int c = 4;}
}

点击view->show byteCode with jclasslib就能够看到字节码
在这里插入图片描述

init方法是类的构造方法,我们点开init下的code,可以清楚的看到字节码执行过程,一开始加载变量a,初始化1,然后进行赋值为10。

 0 aload_01 invokespecial #1 <java/lang/Object.<init> : ()V>4 aload_05 iconst_16 putfield #2 <com/lyd/testboot/jvm/JVM01.a : I>9 aload_0
10 bipush 10
12 putfield #2 <com/lyd/testboot/jvm/JVM01.a : I>
15 return

同样,我们可以在main#code中看到main中成员变量的赋值情况

0 iconst_3
1 istore_1
2 iconst_4
3 istore_2
4 return

我们可以看到开始给b赋值了3,后面给c赋值了4。可见字节码的执行也是按照代码的顺序去执行的。
方法: 这是类的静态初始化块(static initializer),用于静态成员的初始化。静态初始化块的名称是,它包括在类的字节码中,用于执行静态字段的初始化和执行静态初始化块中的代码。静态初始化块在类加载的初始化阶段执行,确保静态成员的初始值被正确设置。
clinit方法是类的静态初始化,我们简单的做个案例,定义一个sta静态变量,并令其值为1,在静态代码块中,我又给他赋值了111,在main方法再次赋值为11,最终静态变量sta的值会是最后的值"11";接着我们在创建一个变量stb,这回,我们把变量的赋值放在之前,在静态代码块之后去声明变量。

public class JVM01 {private int a = 1;public static int sta = 1;public JVM01() {a = 10;}static {sta = 111;stb = 222;}public static int stb = 2;public static void main(String[] args) {int b = 3;int c = 4;JVM01.sta = 11;}
}

我们通过jclasslib-bytecode-viewer插件来看一下字节码
在这里插入图片描述

sta,stb在准备阶段的时候默认值是0(因为是int类型),直到分配内存确认值之后分别赋值为1和2,接着会执行静态代码块,执行的时机是在类被加载到内存中,但在类的实例被创建之前。静态代码块在连接阶段执行,而不是在类的实例化或初始化阶段执行。此时分别会被赋值为111和222,那么sta在main中赋值为11?等静态代码块执行完毕之后就会执行main方法,在执行main方法就会将sta的值赋值为11,所以最终的值也就是11。
我们点开main#code来看一下执行流程,可见被赋值为11。

0 iconst_3
1 istore_1
2 iconst_4
3 istore_2
4 bipush 11
6 putstatic #3 <com/lyd/testboot/jvm/JVM01.sta : I>
9 return

类的加载器

类的加载器负责将类文件加载到内存中,以便在Java程序中使用。类加载器是Java实现动态加载和模块化编程的基础,它有助于实现模块化开发、热部署和插件化架构等功能。主要包括引导类加载器(Bootstrap Class Loader)、扩展类加载器(Extension Class Loader)、应用程序类加载器(Application Class Loader)还有自定义类加载器(User Class Loader)。这些类加载器在jvm启动是自动创建并运行,他们的操作都遵循双亲委派机制,就是在加载类的时候都会向上委托,询问父类加载类,知道所有的父类加载器无法加载的情况下,当前类加载器才会尝试加载。
在这里插入图片描述

1) 三个核心类加载器

简单说一下引导类、扩展类、系统类加载器是什么,每个都有特定的职责和加载类的范围。
① 引导类加载器(Bootstrap Class Loader):
引导类加载器是负责加载核心的Java类库,如java.lang包中的类,以及其他Java平台的关键组件。这些类库通常存储在JVM安装目录下的lib目录中。开发人员无法直接访问引导类加载器,它主要用于加载Java运行时环境的核心类。引导类加载器只会加载包为java、javax、sun等开头的类。
② 扩展类加载器(Extension Class Loader):
扩展类加载器可以通过系统属性java.ext.dirs来指定扩展类库的位置。
③ 系统类加载器(Application Class Loader):
系统类加载器负责加载位于类路径(Classpath)上的类文件,包括用户编写的类和第三方库。大多数Java应用程序都是由系统类加载器加载的,因为它加载位于类路径上的类。
我们可以在代码层面来查看加载器,通过java.lang.ClassLoader#getSystemClassLoader()来获取系统类加载器。得到的ClassLoader类,可以继续ClassLoader#getParent()获取上层的类加载器,也就是扩展加载器,直到最上一层的引导类加载器,此时我们获取的值是为null,由此可见,我们是拿不到引导类加载器。

public class ClassLoadShow {public static void main(String[] args) {// 获取系统类加载器ClassLoader classLoader = ClassLoader.getSystemClassLoader();System.out.println(classLoader);// 获取上层:扩展加载器ClassLoader extClassLoader = classLoader.getParent();System.out.println(extClassLoader);// 继续获取上层加载器: null  获取不到引导类加载器ClassLoader bootstrapClassLoader = extClassLoader.getParent();System.out.println(bootstrapClassLoader);// 获取当前类ClassLoader nowClassLoader = ClassLoadShow.class.getClassLoader();System.out.println(nowClassLoader);// String是根据引导类加载器加载的。Java的核心类库都是System.out.println(String.class.getClassLoader());}
}

接下来我们通过sun.misc.Launcher#getBootstrapClassPath().getURLs()获取引导类路径(Bootstrap Class Path)中的URLs。这些路径内的核心Java类库都是引导类加载器,里面的任何一个类.class#getClassLoader()都是为null。

public static void main(String[] args) {URL[] urLs = Launcher.getBootstrapClassPath().getURLs();for (URL urL : urLs) {System.out.println(urL.toExternalForm());}
}

2) 自定义类加载器

我们还可以通过自定类加载器来定制加载类的方式。

为什么要自定义加载类
  • 隔离加载类
  • 修改类的加载方式
  • 扩展加载方式
  • 防止源码泄露
如何自定义类加载器

① 需要继承java.lang.ClassLoader类,可以选择扩展ClassLoader的子类,以便更容易加载外部类文件。
②需要重写findClass(String name)方法,这个方法负责查找和加载类的字节码。你需要提供自定义的类加载逻辑。
③使用的时候创建一个测试类,实例化你的自定义类加载器,然后使用它来加载类。

package com.lyd.testboot.jvm;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;/*** @Author: lyd* @Date: 2023/10/17 00:08* @Description:*/
public class MyClassLoader extends ClassLoader {// 指定加载类的路径private String classPath;public MyClassLoader(String classPath, ClassLoader parent) {super(parent);this.classPath = classPath;}@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {try {byte[] classData = loadClassData(); // 从文件或其他地方加载类字节码return defineClass(name, classData, 0, classData.length);} catch (Exception e) {e.printStackTrace();}return super.findClass(name);}/*** 使用字节流获取字节数据* @return* @throws IOException*/private byte[] loadClassData() throws IOException {// 这里要读入.class的字节,因此要使用字节流,需要转成绝对路径  D:/Code/Fly.classFile file = new File(classPath);FileInputStream fis = new FileInputStream(file);int length = fis.available();byte[] data = new byte[length];fis.read(data);fis.close();return data;}}

测试的时候,Class.forName有一个三个参数的重载方法,可以指定类加载器,平时我们使用的Class.forName(“XX.XX.XXX”)都是使用的系统类加载器Application ClassLoader。也可以是使用自定义的加载器MyClassLoader#loadClass()。

public class MyClassLoaderTest {public static void main(String[] args) {MyClassLoader myClassLoader = new MyClassLoader("D:\\Code\\Fly.class", ClassLoader.getSystemClassLoader().getParent());try {// 输入外部类的绝对路径
//            Class<?> myClass = myClassLoader.loadClass("com.lyd.testboot.jvm.Fly");Class<?> myClass = Class.forName("com.lyd.testboot.jvm.Fly", true, myClassLoader);Object o = myClass.newInstance();System.out.println(o);System.out.println(o.getClass().getClassLoader());} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}
}

我们可以通过打印的信息看到,是通过我们自定义的类加载器去实现的
在这里插入图片描述

在这里,个人出现最头疼的事情是第二行输出,一直打印出来的是"sun.misc.Launcher$AppClassLoader"。这是因为这个Fly类会自动编译到项目的target目录底下,这下面自然就是由Application ClassLoader加载的。
然而解决方式就是在构造方法加上ClassLoader.getSystemClassLoader().getParent(),把自定义ClassLoader的父加载器设置为Extension ClassLoader,这样父加载器加载不到Person.class,就交由子加载器MyClassLoader来加载了。

3) 双亲委派机制

双亲委派机制(Parent Delegation Model)是Java类加载机制的一个关键概念,它用于描述类加载器在加载类时的工作方式。这个机制的核心思想是,类加载器在加载类时首先尝试委派(delegate)加载请求给其父类加载器,只有在父类加载器无法加载该类时,才会自己尝试加载。
这个机制能够确保类的一致性,避免类被重复加载。
未命名文件 (7).png

① 双亲委派的原理

简单理解就是逐层委托,知道父类加载器加载失败,逐层下来,直到都失败了,最后由当前类加载器加载。那么其原理是什么呢?我们可以由几个概念来学习。
i 委派链
Java类加载器按照层次结构组织,每个类加载器都有一个父类加载器,直到根加载器。这个层次结构构成了一个委派链。
ii 加载类的请求
当一个类加载器得到请求的时候,并不会自己就尝试去加载类,而是不断的委派给父类加载器。
iii 双亲优先
父类加载器优先加载,如果父类加载器能够成功加载请求的类,子类加载器就不再尝试加载。
iv 检查类已加载
在委派链上传递加载请求时,每个类加载器都会首先检查是否已经加载了请求的类。如果类已经加载,就直接返回该类的Class对象,否则继续委派加载请求。
v 根加载器
根加载器(通常是引导类加载器)是类加载器层次结构的顶级,它不具有父加载器。如果根加载器无法加载请求的类,加载请求会向下传递到应用程序类加载器。
vi 应用程序类加载器
应用程序类加载器是Java应用程序的类加载器,它通常是加载应用程序的起点。如果应用程序类加载器无法加载请求的类,加载请求会继续向下传递到扩展类加载器,然后到引导类加载器。

② 双亲委派机制优势
  • 防止类的重复加载
  • 保护程序,防止核心API被篡改
③ 沙箱安全机制

Java虚拟机 (JVM) 中的沙箱安全机制是一种用于保护系统免受不受信任的Java代码的潜在威胁的措施。这种机制是通过多层安全性措施和类加载机制来实现的,以确保Java应用程序在运行时不会执行危险操作或访问敏感资源。就比如说我们自定义了一个String类,这个类是lang包下的,是由引导类加载器加载,引导类会先加载rt.jar中的java\lang\String.class,并且会报错说没有新增的方法。

④ 破坏双亲委派机制

虽然双亲委派机制是默认行为,但在某些情况下,开发人员可能需要破坏这一机制,自定义类加载器以实现特定的类加载行为。通常是在自定义加载器中去重写loadClass或者findClass方法,覆盖

在JVM中,类的完整类名(全限定名)需要完全一致,并且加载器也需要是一样的,这样才能说明是同一个类,如果完整类名一样,但是由不同的类加载器加载,那么这两个类对象就不是同一个。

总结

类加载器子系统是JVM中的重要组件,它是负责加载类,在加载这一过程中还细化了加载、链接、初始化的三个重要阶段。在通过字节码我们可以看出Java的init与clinit方法为静态变量进行初始化与赋值。类的加载是遵循双亲委派机制

博客文献

自定义一个类加载器 - 五月的仓颉 - 博客园
【精选】Java双亲委派模型:为什么要双亲委派?如何打破它?破在哪里?_为什么要打破双亲委派_徐同学呀的博客-CSDN博客

👍创作不易,可能有些语言不是很通畅,如有错误请指正,感谢观看!记得点赞哦!👍

相关文章:

【JVM系列】- 类加载子系统与加载过程

类加载子系统与加载过程 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习心得&#xff0c;欢迎指正…...

Amazon图片下载器:利用Scrapy库完成图像下载任务

概述 本文介绍了如何使用Python的Scrapy库编写一个简单的爬虫程序&#xff0c;实现从Amazon网站下载商品图片的功能。Scrapy是一个强大的爬虫框架&#xff0c;提供了许多方便的特性&#xff0c;如选择器、管道、中间件、代理等。本文将重点介绍如何使用Scrapy的图片管道和代理…...

Unity中Shader的Pass的复用

文章目录 前言一、怎么实现Pass的复用1、给需要引用的Pass给定特定的名字2、在需要引用 Pass 的Shader中&#xff0c;在Pass的平行位置使用 UsePass "ShaderPath PassName" 二、实现一个没被遮挡的部分显示模型原本的样子&#xff0c;遮挡部分显示模型的XRay效果1、…...

vue内容自适应方法

Vue中可以通过以下几种方式实现内容自适应&#xff1a; 使用CSS媒体查询&#xff1a;使用CSS媒体查询可以根据屏幕大小来动态改变元素的样式。例如&#xff0c;可以设置一个div元素在屏幕宽度小于600px时宽度为100%&#xff0c;在屏幕宽度大于600px时宽度为50%。 使用Vue的计算…...

RustDay05------Exercise[41-50]

41.使用模块的函数 mod 是用于创建模块的关键字。模块是一种组织代码的方式&#xff0c;它可以包含函数 (fn)、结构体 (struct)、枚举 (enum)、常量 (const)、其他模块 (mod) 等。模块用于组织和封装代码&#xff0c;帮助将代码分割成可管理的单元。模块可以形成层次结构&…...

C语言实现通讯录(超详细)

1.实现怎样一个通讯录 实现一个通讯录联系人信息&#xff1a;1.可以保存100个人的信息名字2.添加联系人年龄3.删除指定联系人性别4.查找指定联系人电话5.修改指定联系人住址6.排序联系人7.显示所有联系人信息 2.通讯录的实现 2.1创建两个源文件和一个头文件 首先我们创建con…...

【Python机器学习】零基础掌握MinCovDet协方差估计

如何更精准地评估资产的风险和收益? 在投资领域,资产的风险和收益评估是至关重要的。传统的协方差矩阵虽然在某种程度上能反映资产间的关联性,但也存在一定的局限性。例如如果样本数量较少,传统的协方差矩阵可能会出现偏差,从而影响投资决策。 假设现在有一个投资组合,…...

2023年【四川省安全员A证】模拟试题及四川省安全员A证作业模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年四川省安全员A证模拟试题为正在备考四川省安全员A证操作证的学员准备的理论考试专题&#xff0c;每个月更新的四川省安全员A证作业模拟考试祝您顺利通过四川省安全员A证考试。 1、【多选题】36V照明适用的场所条…...

Flask项目log的集成

一、引入log 在项目的init.py文件中&#xff1a; import logging from logging.handlers import RotatingFileHandlerfrom flask_wtf.csrf import CSRFProtect from flask import Flask from flask_sqlalchemy import SQLAlchemy from redis import StrictRedis from flask_s…...

Open3D(C++) 最小二乘拟合平面(拉格朗日乘子法)

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。 一、算法原理 设拟合出的平面方程为: a x + b y + c...

c语言练习93:环形链表的约瑟夫问题

环形链表的约瑟夫问题 环形链表的约瑟夫问题_牛客题霸_牛客网 描述 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。 下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下一个人&#xff0c;问最后留下的这个人编号是…...

从入门到进阶 之 ElasticSearch 文档、分词器 进阶篇

&#x1f339; 以上分享 ElasticSearch 文档、分词器 进阶篇&#xff0c;如有问题请指教写。&#x1f339;&#x1f339; 如你对技术也感兴趣&#xff0c;欢迎交流。&#x1f339;&#x1f339;&#x1f339; 如有需要&#xff0c;请&#x1f44d;点赞&#x1f496;收藏&#…...

亚马逊云科技多项新功能与服务,助力各种规模的组织拥抱生成式 AI

从初创企业到大型企业&#xff0c;各种规模的组织都纷纷开始接触生成式 AI 技术。这些企业希望充分利用生成式 AI&#xff0c;将自身在测试版、原型设计以及演示版中的畅想带到现实场景中&#xff0c;实现生产力的大幅提升并大力进行创新。但是&#xff0c;组织要怎样才能在企业…...

网站布局都有哪些?

网站布局是指网页中各元素的布局方式&#xff0c;以下是一些常见的网站布局&#xff1a; 栅格布局&#xff1a;将页面分成一个个小格子&#xff0c;再把内容放到对应的格子中。这种布局有利于提高网页的视觉一致性和用户体验&#xff0c;是网站设计中最常用的布局方式之一。流…...

第17章 MQ(一)

17.1 谈谈你对MQ的理解 难度:★ 重点:★★ 白话解析 MQ也要有一跟主线,先理解它是什么,从三个方面去理解就好了:1、概念;2、核心功能;3、分类。 1、概念:MQ(Message Queue),消息队列,是基础数据结构中“先进先出”的一种数据结构。指把要传输的数据(消息)放在队…...

LeetCode算法刷题(python) Day41|09动态规划|理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

目录 动规五部曲LeetCode 509. 斐波那契数LeetCode 70. 爬楼梯LeetCode 746. 使用最小花费爬楼梯 动规五部曲 确定dp数组以及下标的含义确定递归公式dp数组如何初始化确定遍历顺序举例推导dp数组 LeetCode 509. 斐波那契数 力扣题目链接 本题最直观是用递归方法 class Sol…...

Spring(四)

1、Spring6整合JUnit 1、JUnit4 User类: package com.songzhishu.spring.bean;import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;/*** BelongsProject: Spring6* BelongsPackage: com.songzhishu.spring.bean*…...

2023-10-8讯飞大模型部署2024秋招后端一面(附详解)

1 mybatis的mapper是什么东西 在MyBatis中&#xff0c;mapper是一个核心概念&#xff0c;它起到了桥梁的作用&#xff0c;连接Java对象和数据库之间的数据。具体来说&#xff0c;mapper可以分为以下两个部分&#xff1a; Mapper XML文件&#xff1a; 这是一个XML文件&#xff…...

如何为 Elasticsearch 创建自定义连接器

了解如何为 Elasticsearch 创建自定义连接器以简化数据摄取过程。 作者&#xff1a;JEDR BLASZYK Elasticsearch 拥有一个摄取工具库&#xff0c;可以从多个来源获取数据。 但是&#xff0c;有时你的数据源可能与 Elastic 现有的提取工具不兼容。 在这种情况下&#xff0c;你可…...

Debian11 安装 OpenJDK8

1. 下载安装包 wget http://snapshot.debian.org/archive/debian-security/20220210T090326Z/pool/updates/main/o/openjdk-8/openjdk-8-jdk_8u322-b06-1~deb9u1_amd64.deb wget http://snapshot.debian.org/archive/debian-security/20220210T090326Z/pool/updates/main/o/op…...

[Machine Learning][Part 6]Cost Function代价函数和梯度正则化

目录 拟合 欠拟合 过拟合 正确的拟合 解决过拟合的方法&#xff1a;正则化 线性回归模型和逻辑回归模型都存在欠拟合和过拟合的情况。 拟合 来自百度的解释&#xff1a; 数据拟合又称曲线拟合&#xff0c;俗称拉曲线&#xff0c;是一种把现有数据透过数学方法来代入一条…...

工业自动化编程与数字图像处理技术

工业自动化编程与数字图像处理技术 编程是计算机领域的基础技能&#xff0c;对于从事软件开发和工程的人来说至关重要。在工业自动化领域&#xff0c;C/C仍然是主流的编程语言&#xff0c;特别是用于工业界面(GUI)编程。工业界面是供车间操作员使用的&#xff0c;使用诸如Hal…...

JY61P.C

/** File Name : JY61P.cDescription : attention © Copyright (c) 2020 STMicroelectronics. All rights reserved.This software component is licensed by ST under Ultimate Liberty licenseSLA0044, the “License”; You may not use this file except in complian…...

Go编程:使用 Colly 库下载Reddit网站的图像

概述 Reddit是一个社交新闻网站&#xff0c;用户可以发布各种主题的内容&#xff0c;包括图片。本文将介绍如何使用Go语言和Colly库编写一个简单的爬虫程序&#xff0c;从Reddit网站上下载指定主题的图片&#xff0c;并保存到本地文件夹中。为了避免被目标网站反爬&#xff0c…...

高性能日志脱敏组件:已支持 log4j2 和 logback 插件

项目介绍 日志脱敏是常见的安全需求。普通的基于工具类方法的方式&#xff0c;对代码的入侵性太强&#xff0c;编写起来又特别麻烦。 sensitive提供基于注解的方式&#xff0c;并且内置了常见的脱敏方式&#xff0c;便于开发。 同时支持 logback 和 log4j2 等常见的日志脱敏…...

一文读懂PostgreSQL中的索引

前言 索引是加速搜索引擎检索数据的一种特殊表查询。简单地说&#xff0c;索引是一个指向表中数据的指针。一个数据库中的索引与一本书的索引目录是非常相似的。 拿汉语字典的目录页&#xff08;索引&#xff09;打比方&#xff0c;我们可以按拼音、笔画、偏旁部首等排序的目录…...

windows的批量解锁

场景 场景是我从github上拉了一个c#项目启动的时候报错&#xff0c; 1>C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64\Microsoft.Common.CurrentVersion.targets(3327,5): error MSB3821: 无法处理文件 UI\Forms\frmScriptBuilder.…...

Nginx配置微服务避免actuator暴露

微服务一般在扫漏洞的情况下&#xff0c;需要屏蔽actuator健康检查 # 避免actuator暴露 if ($request_uri ~ "/actuator") { return 403; }...

GEE——在GEE中计算地形位置指数TPI

简介: DEM中的TPI计算是指通过计算每个像元高程与其邻域高程的差值来计算地形位置指数(Topographic Position Index)。TPI 是描述地形起伏度和地形形态的一个重要指标,可以用于地貌分类、土壤侵蚀、植被分布等领域。 地形位置指数(Topographic Position Index,TPI)是用…...

树的基本操作(数据结构)

树的创建 //结构结点 typedef struct Node {int data;struct Node *leftchild;struct Node *rightchild; }*Bitree,BitNode;//初始化树 void Create(Bitree &T) {int d;printf("输入结点(按0为空结点):");scanf("%d",&d);if(d!0){T (Bitree)ma…...