【实战JVM】-01-JVM通识-字节码详解-类的声明周期-加载器

news2024/11/24 3:33:20

【实战JVM】-01-JVM通识-字节码详解-类的声明周期-加载器

  • 1 初识JVM
    • 1.1 什么是JVM
    • 1.2 JVM的功能
      • 1.2.1 即时编译
    • 1.3 常见JVM
  • 2 字节码文件详解
    • 2.1 Java虚拟机的组成
    • 2.2 字节码文件的组成
      • 2.2.1 正确打开字节码文件
      • 2.2.2 字节码组成
      • 2.2.3 基础信息
        • 2.2.3.1 魔数
        • 2.2.3.1 主副版本号
      • 2.2.4 常量池
      • 2.2.5 方法
    • 2.3 linux中打开字节码文件
    • 2.4 字节码常用工具 Arthas
      • 2.4.1 安装Arthas
      • 2.4.2 Arthas功能
        • 2.4.2.1 获取系统实时面板-dashboard
        • 2.4.2.2 加载特定类的字节码-dump
        • 2.4.2.3 反编译已加载类的源码-jad
        • 2.4.2.4 查看JVM已加载的类信息-sc
  • 3 类的生命周期
    • 3.1 生命周期的概述
    • 3.2 加载阶段
      • 3.2.1 查看内存中的对象
    • 3.3 连接阶段
      • 3.3.1 验证阶段
        • 3.3.1.1 验证是否符合jvm规范
        • 3.3.1.2 元信息验证
        • 3.3.1.3 验证语义
        • 3.3.1.4 符号引用验证
      • 3.3.2 准备阶段
      • 3.3.3 解析阶段
    • 3.4 初始化阶段
      • 3.4.1 笔试题
      • 3.4.2 特殊情况
    • 3.5 总结
  • 4 类的加载器
    • 4.1 类加载器的分类
      • 4.1.1 JDK8之前的分类
      • 4.1.2 使用Arthas查看类加载器-classloader
      • 4.1.3 C++启动类加载器BootstrapClassLoader
      • 4.1.4 Java中默认类加载器
        • 4.1.4.1 扩展类加载器ExtClassLoader
        • 4.1.4.2 应用程序类加载器 AppClassLoader
        • 4.1.4.3 Arthas-classloader高级用法
    • 4.2 类加载器的双亲委派机制
      • 4.2.1 Arthas查看类加载器父子关系
      • 4.2.2 面试
    • 4.3 打破双亲委派机制
      • 4.3.1 自定义类加载器
        • 4.3.1.1 Arthas展示类的详细信息
        • 4.3.1.2 正确的自定义类加载器
      • 4.3.2 线程上下文类加载器
        • 4.3.2.1 SPI机制
        • 4.3.2.2 总结
      • 4.3.3 热部署
        • 4.3.3.1 热更新注意事项
    • 4.4 JDK8之后的类加载器


1 初识JVM

1.1 什么是JVM

在这里插入图片描述
在这里插入图片描述

1.2 JVM的功能

在这里插入图片描述

1.2.1 即时编译

即时编译Just-In-Time 简称JIT进行性能的优化,最终到达接近C、C++的性能

在这里插入图片描述
在这里插入图片描述

将热点代码转换为机器码后保存至RAM,下次执行时直接从RAM中调用。

在这里插入图片描述

1.3 常见JVM

在这里插入图片描述

java -version

在这里插入图片描述

2 字节码文件详解

2.1 Java虚拟机的组成

在这里插入图片描述

2.2 字节码文件的组成

2.2.1 正确打开字节码文件

安装jclasslib

在这里插入图片描述
打开任意一个class文件
在这里插入图片描述

2.2.2 字节码组成

  • 基础信息(一般信息+接口):

    • 魔数、字节码对应的java版本号,访问标识(public、final等),以及这个类父类是哪个,以及实现了哪些接口
  • 常量池:

    • 保存了字符串常量、类、接口名、字段名。主要在字节码指令中使用。
    • 在这里插入图片描述
  • 字段:

    • 当前类或接口的字段信息,包括名字,描述符,访问标识。

    • private final static int a1=0
      
    • 在这里插入图片描述

  • 方法:

    • 当前类或接口的声明的方法信息字节码指令
    • 在这里插入图片描述
  • 属性:

    • 类的属性,比如源码的名字、内部类的列表等
    • 在这里插入图片描述

2.2.3 基础信息

在这里插入图片描述

在这里插入图片描述

2.2.3.1 魔数

在这里插入图片描述

在这里插入图片描述

打开二进制的png文件,就是以89504E47开始的

在这里插入图片描述

jpg则以FFD8FF开始

在这里插入图片描述

java字节码则是以CAFEBABE开始

在这里插入图片描述

2.2.3.1 主副版本号

在这里插入图片描述

52对应jdk1.8 61则对应jdk17

2.2.4 常量池

public class HelloWorld{
    public static final String a1= "a1a1a1";
    public static final String a2= "a1a1a1";
    public static void main(String[] args){

       System.out.println("Hello world!");
    }
}

查看编译后的class文件

在这里插入图片描述

两个都是常量,且指向同一块常量值索引,CONSTANT_String_info存放着cp_info #33,依旧是个索引

在这里插入图片描述

查看cp_info #33,这时候字面量才是a1a1a1

在这里插入图片描述

为什么要两级索引呢?这是因为在jvm中的运行时数据区域中有这方法区,方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

在这里插入图片描述

public class HelloWorld{
    public static final String a1= "abc";
    public static final String a2= "abc";
    public static final String abc= "abc";
    public static void main(String[] args){

       System.out.println("Hello world!");
    }
}

比如字段名和常量名都叫abc,但常量名是abc是String类型,而字段名是无类型的,但是都指向utf8格式的abc

在这里插入图片描述

2.2.5 方法

public static void main(String[] args){
    int i=0;
    i=i++;
    System.out.println(i);
}

对应字节码:

 0 iconst_0   			//操作数栈: [] -> [0],将常量值0压入操作数栈。
 1 istore_1   			//操作数栈: [0] -> [],将操作数栈顶的整数值(0)存入本地变量1。
 2 iload_1    			//操作数栈: [] -> [0],将本地变量1中的整数值(0)加载到操作数栈。
 3 iinc 1 by 1 			//本地变量1的值增加1。原值是0,现在变为1。
 6 istore_1				//操作数栈: [0] -> [],将操作数栈顶的整数值存入本地变量1。本地变量: [1]-> [0],
 7 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>  //获取System.out的值并压入操作数栈。
10 iload_1				//操作数栈: [Ljava/io/PrintStream;] -> [Ljava/io/PrintStream;, 0],将本地变量1中的整数值加载到操作数栈。
11 invokevirtual #3 <java/io/PrintStream.println : (I)V>
14 return

i处于局部变量表的1号位

在这里插入图片描述

如果换成++i

public static void main(String[] args){
    int i=0;
    i=++i;
    System.out.println(i);
}
 0 iconst_0
 1 istore_1				//0放到本地变量表
 2 iinc 1 by 1			//本地变量表先自增,0->1
 5 iload_1				//将本地变量1中的整数值(1)加载到操作数栈。
 6 istore_1				//操作数栈: [1] -> [],将操作数栈顶的整数值存入本地变量1。本地变量: [1]-> [1],
 7 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
10 iload_1
11 invokevirtual #3 <java/io/PrintStream.println : (I)V>
14 return

这样就不会发生i=i++这种覆盖赋值的情况了。

作业:

int i=0,j=0,k=0;
i++;
j=j+1;
k+=1;

i和k一样快,都是把0从操作数栈中放入本地变量中直接操作本地变量自增。

j最慢,从本地变量表中加载到操作数栈中,再加载1,再相加,再放入本地变量表。

2.3 linux中打开字节码文件

在这里插入图片描述

javap -v 字节码文件名称

2.4 字节码常用工具 Arthas

2.4.1 安装Arthas

在这里插入图片描述

启动arthas

在这里插入图片描述

先启动项目再分析

public class ArthasDemo {
    public static void main(String[] args) {
        while (true) {
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在arthas工作目录中启动

java -Dfile.encoding=UTF-8 -jar arthas-boot.jar

-Dfile.encoding=UTF-8是让arthas以utf8格式启动,这样不会乱码
在这里插入图片描述

成功捕获到ArthasDemo,选择3回车进入arthas内部,他还自动下载了arthas3.7.2版本

3

在这里插入图片描述

2.4.2 Arthas功能

在这里插入图片描述

2.4.2.1 获取系统实时面板-dashboard

在这里插入图片描述

我们设置每隔两秒刷新一次,刷新3次

dashboard -i 2000 -n 3

在这里插入图片描述

只显示1次

在这里插入图片描述

2.4.2.2 加载特定类的字节码-dump

在这里插入图片描述

dump -d D:/File/StudyJavaFile/JavaStudy/JVM/low/day01/resource/ com.sjb.arthas.ArthasDemo

在这里插入图片描述

在这里插入图片描述

这样就获取了运行时的java文件的字节码信息

2.4.2.3 反编译已加载类的源码-jad
jad com.sjb.arthas.ArthasDemo

在这里插入图片描述

和我们的源码几乎一致

案例

在这里插入图片描述

启动springboot-classfile后

在这里插入图片描述

public UserVO user(@PathVariable("type") Integer type,@PathVariable("id") Integer id){
    //前边有一大堆逻辑,巴拉巴拉
    if(type==UserType.REGULAR.getType()){
        return new UserVO(id,"普通用户无权限查看");
    }
    return new UserVO(id,"这是尊贵的收费用户才能看的秘密!");
}

不能用==来判断类型,需要equals

在这里插入图片描述

在这里插入图片描述

即使是普通用户,但是因为用的==判断的类型,也能进入vip用户

使用jad查看

jad com.itheima.springbootclassfile.controller.UserController

在这里插入图片描述

定位到问题信息,以供以后热更新

2.4.2.4 查看JVM已加载的类信息-sc

在这里插入图片描述

sc -d 类名(java.lang.String)

查看当前类的类加载器,如果为空,则为启动类加载器。

3 类的生命周期

3.1 生命周期的概述

在这里插入图片描述

3.2 加载阶段

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.2.1 查看内存中的对象

推荐使用JDK自带的hsdb工具查看Java虚拟机内部的内存信息。工具位于JDK安装目录下的lib文件夹的sa-jdi.jar中。

启动jvm项目的HsdbDemo

在这里插入图片描述

使用jps展示当前所有的java进程及id

jps

在这里插入图片描述

启动命令

D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\lib>java -cp sa-jdi.jar sun.jvm.hotspot.HSDB

在这里插入图片描述

输入我们要找的类的编号HsdbDemo:18648

在这里插入图片描述

直接搜索HsdbDemo,因为我们只new了一次,自然只有一个对象。

在这里插入图片描述

在这里插入图片描述

一句话概括:类加载器将类的信息加载到内存中,java虚拟机在方法区和堆区中各分配一个对象去保存这个信息,而我们需要操作的则是堆区中的对象,jdk8之后静态字段也是存在堆中的

3.3 连接阶段

在这里插入图片描述

3.3.1 验证阶段

3.3.1.1 验证是否符合jvm规范

在这里插入图片描述

3.3.1.2 元信息验证

在这里插入图片描述

3.3.1.3 验证语义

在这里插入图片描述

3.3.1.4 符号引用验证

判断是否访问了其他类的private方法。

3.3.2 准备阶段

在这里插入图片描述
value在准备阶段分配的值是默认值0,而赋值为1是初始化阶段做的事

在这里插入图片描述

但是也有例外,如果是final修饰的基本数据类型,会在准备阶段直接将代码中的值进行赋值。

public static final int value=1;

3.3.3 解析阶段

在这里插入图片描述

直接引用不在使用编号,而是直接使用内存中的地址进行访问具体的数据。

3.4 初始化阶段

  • 初始化阶段会执行静态代码中的代码,并为静态变量赋值
  • 初始化阶段会执行字节码文件中的clinit部分的字节码指令。

在这里插入图片描述

如果颠倒一下顺序,那么输出则是1

在这里插入图片描述

因为静态变量是在连接阶段准备阶段完成默认初始化。然后再赋为2,再赋为1。

在这里插入图片描述

3.4.1 笔试题

(1)

在这里插入图片描述

构造代码块先于构造方法前执行

3.4.2 特殊情况

在这里插入图片描述

  • 直接访问父类的静态变量,不会触发子类的初始化。

  • 子类的初始化clinit调用之前,会先调用父类的clinit初始化方法。
    在这里插入图片描述

  • 数组的创建不会导致数组中元素的类进行初始化。

    • 是因为创建数组时是创建的数组的对象,而不是数组中元素的对象。所以数组中元素的类不会进行初始化。
  • 如果一个变量用final修饰,并且其中的内容要执行指令才能得出结果,那么会在clinit方法中进行初始化。

3.5 总结

在这里插入图片描述

4 类的加载器

类加载器是jvm提供给应用程序去实现获取类和接口字节码数据的技术。

负责在类加载过程中的字节码获取并且加载到内存这一部分。通过加载字节码数据放入内存转换成byte[],接下来调用虚拟机底层的方法将byte[]转换成方法区和堆中的数据。

4.1 类加载器的分类

在这里插入图片描述

俩下Shift是搜索
Ctrl+Alt+类是找当前类的所有实现

4.1.1 JDK8之前的分类

在这里插入图片描述

  • 引导类加载器 Bootstrap,加载属于JVM的一部分,由C++代码实现,负责加载<JAVA_HOME\>\jre\lib路径下的核心类库
  • 扩展类加载器 ExtClassLoader,扩展类加载器负责加载<JAVA_HOME>\jre\lib\ext目录下的类库。
  • 应用程序类加载器 AppClassLoader,应用程序类加载器负责加载 classpath环境变量所指定的类库,是用户自定义类的默认类加载器。

4.1.2 使用Arthas查看类加载器-classloader

在这里插入图片描述

启动Hsdbdemo后打开arthas,在arthas工作目录中启动

java -jar arthas-boot.jar

进入Hsdbdemo

classloader

在这里插入图片描述

4.1.3 C++启动类加载器BootstrapClassLoader

负责加载<JAVA_HOME\>\jre\lib路径下的核心类库

通过类名.class.getClassLoader来获取当前类的类加载器。

在这里插入图片描述

添加java虚拟机参数D:/jvm/jar/classloader-test.jar是jar包地址

-Xbootclasspath/a:D:/jvm/jar/classloader-test.jar

4.1.4 Java中默认类加载器

在这里插入图片描述

4.1.4.1 扩展类加载器ExtClassLoader

扩展类加载器 ExtClassLoader,扩展类加载器负责加载<JAVA_HOME>\jre\lib\ext目录下的类库。

在这里插入图片描述

添加java虚拟机参数D:/jvm/jar/classloader-test.jar是jar包地址。

不仅需要jar包的地址,还需要原来ext的地址D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\jre\lib\ext

-Djava.ext.dirs="D:\Software\software_with_code\idea\jdk\jdk1.8.0_381\jre\lib\ext;D:/jvm/jar/classloader-test.jar"

在windows中;是追加,linux和mac中:是追加,尽量用双引号引起俩,以免因为特殊字符报错。

4.1.4.2 应用程序类加载器 AppClassLoader

应用程序类加载器 AppClassLoader,应用程序类加载器负责加载 classpath环境变量所指定的类库,是用户自定义类的默认类加载器。既可以加载当前项目中创建的类,也可以加载maven依赖中包含的类。

4.1.4.3 Arthas-classloader高级用法
classloader -l

在这里插入图片描述

查看当前所有的类加载器以及其哈希值

classloader -c hash值

在这里插入图片描述

查看当前查询的类加载器加载的所有jar包

在这里插入图片描述

4.2 类加载器的双亲委派机制

jvm中有多个类加载器,双亲委派机制的核心就是解决一个类到底由谁加载的问题。

双亲委派机制的作用

  1. 保证类加载的安全性

    通过双亲委派机制避免恶意代码替换JDK中的核心类库,比如Java.lang.String,确保核心类库的完整性和安全性。

  2. 避免重复加载

    双亲委派机制可以避免同一个类被多次加载

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.2.1 Arthas查看类加载器父子关系

classloader -t

在这里插入图片描述

4.2.2 面试

在这里插入图片描述

4.3 打破双亲委派机制

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.3.1 自定义类加载器

在这里插入图片描述

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
    if(name.startsWith("java.")){
        return super.loadClass(name);
    }
    byte[] data = loadClassData(name);
    return defineClass(name, data, 0, data.length);
}

public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
    BreakClassLoader1 classLoader1 = new BreakClassLoader1();
    classLoader1.setBasePath("D:\\lib\\");
    Class<?> clazz1 = classLoader1.loadClass("com.itheima.my.A");
    BreakClassLoader1 classLoader2 = new BreakClassLoader1();
    classLoader2.setBasePath("D:\\lib\\");
    Class<?> clazz2 = classLoader2.loadClass("com.itheima.my.A");
    System.out.println(clazz1 == clazz2);
    Thread.currentThread().setContextClassLoader(classLoader1);
    System.out.println(Thread.currentThread().getContextClassLoader());
    System.in.read();
 }

重写loadClass方法,删除双亲委派机制,如果是java开头的jar包,就交给原先父类的loadClass,如果是自定义的,就自己直接加载。

自定义类加载器没指定双亲的话,默认双亲为应用程序类加载器

在这里插入图片描述

4.3.1.1 Arthas展示类的详细信息
sc -d com.itheima.my.A

在这里插入图片描述

因为刚刚用两个不同的类加载器加载com.itheima.my.A,自然得到两个不同的对象

4.3.1.2 正确的自定义类加载器

在这里插入图片描述

4.3.2 线程上下文类加载器

在这里插入图片描述

DriverManager类位于rt.jar包中,由启动类加载器加载。

在这里插入图片描述

4.3.2.1 SPI机制

SPI全程Service Provider Interface,是JDK内置的一种服务提供发现的机制

需要在resources目录下新建META-INF/services目录,并且在这个目录下新建一个与上述接口的全限定名一致的文件java.sql.Driver的接口,在这个文件中写入接口的实现类的全限定名com.mysql.cj.jdbc.Driver。

在这里插入图片描述

ServiceLoader这个类的源码如下:

public final class ServiceLoader<S> implements Iterable<S> {
    //扫描目录前缀
    private static final String PREFIX = "META-INF/services/";
    // 被加载的类或接口
    private final Class<S> service;
    // 用于定位、加载和实例化实现方实现的类的类加载器
    private final ClassLoader loader;
    // 上下文对象
    private final AccessControlContext acc;
    // 按照实例化的顺序缓存已经实例化的类
    private LinkedHashMap<String, S> providers = new LinkedHashMap<>();
    // 懒查找迭代器
    private java.util.ServiceLoader.LazyIterator lookupIterator;
    // 私有内部类,提供对所有的service的类的加载与实例化
    private class LazyIterator implements Iterator<S> {
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        String nextName = null;
        //...
        private boolean hasNextService() {
            if (configs == null) {
                try {
                    //获取目录下所有的类
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    //...
                }
                //....
            }
        }
        private S nextService() {
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                //反射加载类
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
            }
            try {
                //实例化
                S p = service.cast(c.newInstance());
                //放进缓存
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                //..
            }
            //..
        }
    }
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在线程中使用

Thread.currentThread().getContextClassLoader()

默认获得的是应用程序类加载器

4.3.2.2 总结

在这里插入图片描述

在这里插入图片描述

所以说,打破双亲委派机制的唯一方法就是重写loadClass或者findClass方法

4.3.3 热部署

在这里插入图片描述

  1. 启动SpringbootClassfileApplication后,使用arthas进入,反编译出UserController

    java -Dfile.encoding=UTF-8 -jar arthas-boot.jar
    
    jad --source-only com.itheima.springbootclassfile.controller.UserController > "D:\Code\JavaCode\JVM\hot-replace\UserController.java"
    

在这里插入图片描述

修改为

if (type.equals(UserType.REGULAR.getType())) {
  1. 编译成字节码文件,如果直接编译,则会因为找不到类加载器而报错,所以需要先找到UserController.java的类加载器,获取其哈希值。

    sc -d com.itheima.springbootclassfile.controller.UserController
    

    在这里插入图片描述

  2. mc -c指定类加载器的哈希码 -d指定输出目录

    mc -c 18b4aac2 "D:\Code\JavaCode\JVM\hot-replace\UserController.java" -d "D:\Code\JavaCode\JVM\hot-replace"
    

    在这里插入图片描述

  3. 通过retransform

    retransform "D:\Code\JavaCode\JVM\hot-replace\com\itheima\springbootclassfile\controller\UserController.class"
    

    在这里插入图片描述

  4. 用jad查看热部署是否完成

    在这里插入图片描述

  5. 发送http请求

    在这里插入图片描述

    说明热部署已经完成

4.3.3.1 热更新注意事项

在这里插入图片描述

4.4 JDK8之后的类加载器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

应用类加载器和扩展类加载器都是继承关系从URLClassLoader变为BuiltinClassLoader,没有太大的区别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1686111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java 数组的基本使用

目录 含义语法格式语句特点数组的长度数组的元素打印数组显示数组数组的复制扩展示例【12】&#xff1a; 含义 数组&#xff08;array&#xff09;是一种最简单的复合数据类型&#xff0c;它是有序数据的集合&#xff0c;数组中的每个元素具有相同的数据类型&#xff0c;可以用…

一款好用的SSH连接工具-Tabby Terminal 使用教程

简介 Tabby Terminal 是一款现代化的终端应用程序&#xff0c;旨在提供流畅、高效且可定制的用户体验。它具有跨平台兼容性&#xff0c;支持多种操作系统&#xff0c;包括 Windows、macOS 和 Linux。其界面设计简洁美观&#xff0c;允许用户通过插件和主题进行个性化定制。同时…

LeetCode674:最长连续递增序列

题目描述 给定一个未经排序的整数数组&#xff0c;找到最长且 连续递增的子序列&#xff0c;并返回该序列的长度。 连续递增的子序列 可以由两个下标 l 和 r&#xff08;l < r&#xff09;确定&#xff0c;如果对于每个 l < i < r&#xff0c;都有 nums[i] < nums…

selenium 爬取今日头条

由于今日头条网页是动态渲染&#xff0c;再加上各种token再验证&#xff0c;因此直接通过API接口获取数据难度很大&#xff0c;本文使用selenium来实现新闻内容爬取。 selenium核心代码 知识点&#xff1a; 代码中加了很多的异常处理&#xff0c;保证错误后重试&#xff0c;…

抖音:当之无愧的短视频NO.1,新老用户奖励丰厚

论起短视频&#xff0c;如不提行业老大抖音&#xff0c;那是说不过去的。年底抖音也加入了波涛汹涌的红包大战&#xff0c;小伙伴们动动手指就能赚到真金白银的现金&#xff0c;何乐而不为&#xff01; 抖音简介 抖音是北京微播视界科技有限公司于2016年9月20日上线的一款音乐…

系统分析与校正方法——时域法

一、概述 时域法是一种直接在时间域中对系统进行分析和校正的方法。 优点&#xff1a;可以提供系统时间响应的全部信息&#xff0c;直观、准确。缺点&#xff1a;研究系统参数改变引起系统性能指标变化的趋势&#xff0c;及对系统进行校正设计时&#xff0c;时域法不是非常方…

钉钉算是在线办公系统的设计标杆,尽管它依然很难用

不吹不黑&#xff0c;钉钉界面谁的的确简洁&#xff0c;无奈它面向的是场景复杂的办公领域&#xff0c;导致其越来越臃肿难用&#xff0c;反正我是该研究研究&#xff0c;但绝对不会用的。 举报 评论 1

【Axure教程】拖动换位选择器

拖动换位选择器通常用于从一个列表中选择项目并将其移动到另一个列表中。用户可以通过拖动选项来实现选择和移动。这种交互方式在许多Web应用程序中很常见&#xff0c;特别是在需要对项目分组的情况下。 所以今天作者就教大家怎么在Axure用中继器制作一个拖动换位选择器的原型…

RK3568笔记二十五:RetinaFace人脸检测训练部署

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 Retinaface是来自insightFace的又一力作&#xff0c;基于one-stage的人脸检测网络。RetinaFace是在RetinaNet基础上引申出来的人脸检测框架&#xff0c;所以大致结构和RetinaNet非常像。 官方提供两种主干特征提取网…

4月手机行业线上市场销售数据分析

政府对智能手机行业的支持政策&#xff0c;如5G推广&#xff0c;以及相关的产业政策&#xff0c;都在一定程度上推动了智能手机市场的发展&#xff0c;再加上AI应用的推广和全球科技迅猛发展&#xff0c;中国手机市场在2024年迎来了恢复性增长。 据鲸参谋数据统计&#xff0c;…

鸟击防治设备 | 机场专用声光定向驱鸟系统分析

飞机与鸟类相撞&#xff0c;导致飞机受损&#xff0c;鸟类死亡&#xff0c;这被称作“鸟击事故”。全球范围内&#xff0c;每年都会发生多起鸟击事件&#xff0c;而大部分的鸟击都发生在飞机起降或低空飞行的阶段。因此&#xff0c;机场需要驱鸟、防鸟&#xff0c;确保鸟类远离…

Unity 直线间隔放置物体

直线间隔放置物体 设置 间隔距离 和 预制体在Scene中拖动即可按间隔距离实例化物体物体的朝向始终朝向统一方向&#xff0c;并且可以在Scene中拖拽更改 传送门

5.2 Go 参数传递

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

RocketMQ实战教程之RocketMQ安装(含Docker安装,建议收藏!)

RocketMQ实战教程之RocketMQ安装 这里实例采用centos系统天翼云为例,分别采用传统安装以及Docker安装的方式来进行RocketMQ的安装.JDK8我这边已经安装配置好了,这里就不在赘述.直接进入正题: 传统安装包安装 系统要求 64位操作系统&#xff0c;推荐 Linux/Unix/macOS64位 JDK…

el-table-column两种方法处理特殊字段,插槽和函数

问题&#xff1a;后端返回的字段为数字 解决办法&#xff1a; {{ row[item.prop] 1 ? "启用" : "禁用" }} {{ row[item.prop] }} 最终果&#xff1a; 另外&#xff1a;如果多种状态时可用函数 {{ getStatus(row[item.prop]) }} {{ row[item.prop…

java技术:oauth2协议

目录 一、黑马程序员Java进阶教程快速入门Spring Security OAuth2.0认证授权详解 1、oauth服务 WebSecurityConfig TokenConfig AuthorizationServer 改写密码校验逻辑实现类 2、oauth2支持的四种方式&#xff1a; 3、oauth2授权 ResouceServerConfig TokenConfig 4、…

linux---进程通信

提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、匿名管道 进程之间的通信目的一般是来控制另一个进程。也可以用来实现数据的交流&#xff0c;还有资源共享等。 匿名管道原理&#xff1a; &#xff08;铺垫&#xff09;进程之间是具有独立性&…

mysql实战——xtrabackup全量备份/增量备份及恢复

一、测试前准备 mysql数据库 端口3306数据文件目录 /data/mysql/3306/data 安装目录/usr/lcoal/mysql配置文件/etc/my.cnf 创建数据库 testXtra 创建备份目录 备份目录/data/backup/备份恢复数据文件目录/data/mysql/3307/data备份恢复配置文件/etc/my_3307.cnf 二、开始…

宠物医院兽医电子处方管理系统软件操作教程,佳易王兽医处方软件分享

试用超级版宠物医院兽医处方管理系统软件V17.3&#xff0c;软件功能实用&#xff0c;操作简单。试用版免费试用&#xff0c;技术支持可以联系客服。 一、软件下载说明及软件操作教程链接 软件下载请点击最下方官网卡片进入 1、软件下载注意事项 【特别说明&#xff1a;下载的…

比亚迪一4S店着火:浅述烟火识别技术与消防安全预警方案的必要性

据新闻报道&#xff0c;2024年5月16日&#xff0c;福建福州一家比亚迪4S店发生火灾。事发后&#xff0c;当地消防立即调员赶往现场救援&#xff0c;大火导致展厅展车基本烧毁&#xff0c;部分维修车辆受损&#xff0c;没有人员伤亡。 随着汽车市场的不断扩大&#xff0c;4S店作…