九、Java 16 新特性

news2024/12/26 11:53:07

九、Java 16 新特性

JDK 16 在 2021 年 3 月 16 号发布!根据发布的规划,这次发布的 JDK 17 是一个长期维护的版本(LTS)。Java 16 提供了数千个性能稳定性安全性更新,以及 17 个 JEP(JDK 增强提案),进一步改进了 Java 语言和平台,以帮助开发人员提高工作效率。

1、知识体系

在这里插入图片描述

2、语言特性增强

1、JEP 394: instanceof 模式匹配(正式版)

模式匹配(Pattern Matching)最早在 Java 14 中作为预览特性引入,在 Java 15 中还是预览特性,在Java 16中成为正式版。模式匹配通过对 instacneof 运算符进行模式匹配来增强 Java 编程语言。

如下内容来自Java14

对 instanceof 的改进,主要目的是为了让创建对象更简单、简洁和高效,并且可读性更强、提高安全性。

在以往实际使用中,instanceof 主要用来检查对象的类型,然后根据类型对目标对象进行类型转换,之后进行不同的处理、实现不同的逻辑,具体可以参考如下:

if (person instanceof Student) {
    Student student = (Student) person;
    student.say();
   // other student operations
} else if (person instanceof Teacher) {
    Teacher teacher = (Teacher) person;
    teacher.say();
    // other teacher operations
}

上述代码中,我们首先需要对 person 对象进行类型判断,判断 person 具体是 Student 还是 Teacher,因为这两种角色对应不同操作,亦即对应到的实际逻辑实现,判断完 person 类型之后,然后强制对 person 进行类型转换为局部变量,以方便后续执行属于该角色的特定操作。

上面这种写法,有下面两个问题:

  • 每次在检查类型之后,都需要强制进行类型转换。
  • 类型转换后,需要提前创建一个局部变量来接收转换后的结果,代码显得多余且繁琐。

对 instanceof 进行模式匹配改进之后,上面示例代码可以改写成:

if (person instanceof Student student) {
    student.say();
   // other student operations
} else if (person instanceof Teacher teacher) {
    teacher.say();
    // other teacher operations
} 

首先在 if 代码块中,对 person 对象进行类型匹配,校验 person 对象是否为 Student 类型,如果类型匹配成功,则会转换为 Student 类型,并赋值给模式局部变量 student,并且只有当模式匹配表达式匹配成功是才会生效和复制,同时这里的 student 变量只能在 if 块中使用,而不能在 else if/else 中使用,否则会报编译错误。

注意,如果 if 条件中有 && 运算符时,当 instanceof 类型匹配成功,模式局部变量的作用范围也可以相应延长,如下面代码:

if (obj instanceof String s && s.length() > 5) {.. s.contains(..) ..} 

另外,需要注意,这种作用范围延长,并不适用于或 || 运算符,因为即便 || 运算符左边的 instanceof 类型匹配没有成功也不会造成短路,依旧会执行到||运算符右边的表达式,但是此时,因为 instanceof 类型匹配没有成功,局部变量并未定义赋值,此时使用会产生问题。

与传统写法对比,可以发现模式匹配不但提高了程序的安全性、健壮性,另一方面,不需要显式的去进行二次类型转换,减少了大量不必要的强制类型转换。模式匹配变量在模式匹配成功之后,可以直接使用,同时它还被限制了作用范围,大大提高了程序的简洁性、可读性和安全性。instanceof 的模式匹配,为 Java 带来的有一次便捷的提升,能够剔除一些冗余的代码,写出更加简洁安全的代码,提高码代码效率。

2、JEP 395: Records (正式版)

Records 最早在 Java 14 中作为预览特性引入,在 Java 15 中还是预览特性,在Java 16中成为正式版。

如下内容来自Java14

Record 类型允许在代码中使用紧凑的语法形式来声明类,而这些类能够作为不可变数据类型的封装持有者。Record 这一特性主要用在特定领域的类上;与枚举类型一样,Record 类型是一种受限形式的类型,主要用于存储、保存数据,并且没有其它额外自定义行为的场景下。

在以往开发过程中,被当作数据载体的类对象,在正确声明定义过程中,通常需要编写大量的无实际业务、重复性质的代码,其中包括:构造函数、属性调用、访问以及 equals() 、hashCode()、toString() 等方法,因此在 Java 14 中引入了 Record 类型,其效果有些类似 Lombok 的 @Data 注解、Kotlin 中的 data class,但是又不尽完全相同,它们的共同点都是类的部分或者全部可以直接在类头中定义、描述,并且这个类只用于存储数据而已。对于 Record 类型,具体可以用下面代码来说明:

public record Person(String name, int age) {
    public static String address;

    public String getName() {
        return name;
    }
}

对上述代码进行编译,然后反编译之后可以看到如下结果:

public final class Person extends java.lang.Record {
    private final java.lang.String name;
    private final java.lang.String age;

    public Person(java.lang.String name, java.lang.String age) { /* compiled code */ }

    public java.lang.String getName() { /* compiled code */ }

    public java.lang.String toString() { /* compiled code */ }

    public final int hashCode() { /* compiled code */ }

    public final boolean equals(java.lang.Object o) { /* compiled code */ }

    public java.lang.String name() { /* compiled code */ }

    public java.lang.String age() { /* compiled code */ }
}  

根据反编译结果,可以得出,当用 Record 来声明一个类时,该类将自动拥有下面特征:

  • 拥有一个构造方法
  • 获取成员属性值的方法:name()、age()
  • hashCode() 方法和 euqals() 方法
  • toString() 方法
  • 类对象和属性被 final 关键字修饰,不能被继承,类的示例属性也都被 final 修饰,不能再被赋值使用。
  • 还可以在 Record 声明的类中定义静态属性、方法和示例方法。注意,不能在 Record 声明的类中定义示例字段,类也不能声明为抽象类等。

可以看到,该预览特性提供了一种更为紧凑的语法来声明类,并且可以大幅减少定义类似数据类型时所需的重复性代码。

另外 Java 14 中为了引入 Record 这种新的类型,在 java.lang.Class 中引入了下面两个新方法:

RecordComponent[] getRecordComponents()
boolean isRecord()   

其中 getRecordComponents() 方法返回一组 java.lang.reflect.RecordComponent 对象组成的数组,java.lang.reflect.RecordComponent也是一个新引入类,该数组的元素与 Record 类中的组件相对应,其顺序与在记录声明中出现的顺序相同,可以从该数组中的每个 RecordComponent 中提取到组件信息,包括其名称、类型、泛型类型、注释及其访问方法。

而 isRecord() 方法,则返回所在类是否是 Record 类型,如果是,则返回 true。

3、新工具和库

1、JEP 380:Unix-Domain 套接字通道

Unix-domain 套接字一直是大多数 Unix 平台的一个特性,现在在 Windows 10 和 Windows Server 2019 也提供了支持。此特性为 java.nio.channels 包的套接字通道和服务器套接字通道 API 添加了 Unix-domain(AF_UNIX)套接字支持。它扩展了继承的通道机制以支持 Unix-domain 套接字通道和服务器套接字通道。Unix-domain 套接字用于同一主机上的进程间通信(IPC)。它们在很大程度上类似于 TCP/IP,区别在于套接字是通过文件系统路径名而不是 Internet 协议(IP)地址和端口号寻址的。对于本地进程间通信,Unix-domain 套接字比 TCP/IP 环回连接更安全、更有效。

2、JEP 390: 对基于值的类发出警告

JDK9注解@Deprecated得到了增强,增加了 since 和 forRemoval 两个属性,可以分别指定一个程序元素被废弃的版本,以及是否会在今后的版本中被删除。JDK16中对@jdk.internal.ValueBased注解加入了基于值的类的告警,所以继续在 Synchronized 同步块中使用值类型,将会在编译期和运行期产生警告,甚至是异常。

  • JDK9中@Deprecated增强了增加了 since 和 forRemoval 两 个属性

JDK9注解@Deprecated得到了增强,增加了 since 和 forRemoval 两个属性,可以分别指定一个程序元素被废弃的版本,以及是否会在今后的版本中被删除。

在如下的代码中,表示PdaiDeprecatedTest这个类在JDK9版本中被弃用并且在将来的某个版本中一定会被删除。

@Deprecated(since="9", forRemoval = true)
public class PdaiDeprecatedTest {

}  
  • JDK16中对基于值的类(@jdk.internal.ValueBased)给出告警

在JDK9中我们可以看到Integer.java类构造函数中加入了@Deprecated(since="9"),表示在JDK9版本中被弃用并且在将来的某个版本中一定会被删除

public final class Integer extends Number implements Comparable<Integer> {

// ... 
    /**
     * Constructs a newly allocated {@code Integer} object that
     * represents the specified {@code int} value.
     *
     * @param   value   the value to be represented by the
     *                  {@code Integer} object.
     *
     * @deprecated
     * It is rarely appropriate to use this constructor. The static factory
     * {@link #valueOf(int)} is generally a better choice, as it is
     * likely to yield significantly better space and time performance.
     */
    @Deprecated(since="9")
    public Integer(int value) {
        this.value = value;
    }
// ... 

} 

如下是JDK16中Integer.java的代码

/*
* <p>This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
 * class; programmers should treat instances that are
 * {@linkplain #equals(Object) equal} as interchangeable and should not
 * use instances for synchronization, or unpredictable behavior may
 * occur. For example, in a future release, synchronization may fail.
 *
 * <p>Implementation note: The implementations of the "bit twiddling"
 * methods (such as {@link #highestOneBit(int) highestOneBit} and
 * {@link #numberOfTrailingZeros(int) numberOfTrailingZeros}) are
 * based on material from Henry S. Warren, Jr.'s <i>Hacker's
 * Delight</i>, (Addison Wesley, 2002).
 *
 * @author  Lee Boynton
 * @author  Arthur van Hoff
 * @author  Josh Bloch
 * @author  Joseph D. Darcy
 * @since 1.0
 */
@jdk.internal.ValueBased
public final class Integer extends Number
        implements Comparable<Integer>, Constable, ConstantDesc {

// ... 
  /**
    * Constructs a newly allocated {@code Integer} object that
    * represents the specified {@code int} value.
    *
    * @param   value   the value to be represented by the
    *                  {@code Integer} object.
    *
    * @deprecated
    * It is rarely appropriate to use this constructor. The static factory
    * {@link #valueOf(int)} is generally a better choice, as it is
    * likely to yield significantly better space and time performance.
    */
  @Deprecated(since="9", forRemoval = true)
  public Integer(int value) {
      this.value = value;
  }
// ...

添加@jdk.internal.ValueBased@Deprecated(since="9", forRemoval = true)的作用是什么呢?

  1. JDK设计者建议使用Integer a = 10或者Integer.valueOf()函数,而不是new Integer(),让其抛出告警?

在构造函数上都已经标记有@Deprecated(since=“9”, forRemoval = true)注解,这就意味着其构造函数在将来会被删除,不应该在程序中继续使用诸如new Integer(); 如果继续使用,编译期将会产生’Integer(int)’ is deprecated and marked for removal 告警。

  1. 在并发环境下,Integer 对象根本无法通过 Synchronized 来保证线程安全,让其抛出告警?

由于JDK中对@jdk.internal.ValueBased注解加入了基于值的类的告警,所以继续在 Synchronized 同步块中使用值类型,将会在编译期和运行期产生警告,甚至是异常。

public void inc(Integer count) {
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            synchronized (count) { // 这里会产生编译告警
                count++;
            }
        }).start();
    }
} 

3、JEP 392:打包工具(正式版)

此特性最初是作为 Java 14 中的一个孵化器模块引入的,该工具允许打包自包含的 Java 应用程序。它支持原生打包格式,为最终用户提供自然的安装体验,这些格式包括 Windows 上的 msi 和 exe、macOS 上的 pkg 和 dmg,还有 Linux 上的 deb 和 rpm。它还允许在打包时指定启动时参数,并且可以从命令行直接调用,也可以通过 ToolProvider API 以编程方式调用。注意 jpackage 模块名称从 jdk.incubator.jpackage 更改为 jdk.jpackage。这将改善最终用户在安装应用程序时的体验,并简化了“应用商店”模型的部署。

4、JEP 396:默认强封装 JDK 内部元素

此特性会默认强封装 JDK 的所有内部元素,但关键内部 API(例如 sun.misc.Unsafe)除外。默认情况下,使用早期版本成功编译的访问 JDK 内部 API 的代码可能不再起作用。鼓励开发人员从使用内部元素迁移到使用标准 API 的方法上,以便他们及其用户都可以无缝升级到将来的 Java 版本。强封装由 JDK 9 的启动器选项–illegal-access 控制,到 JDK 15 默认改为 warning,从 JDK 16 开始默认为 deny。(目前)仍然可以使用单个命令行选项放宽对所有软件包的封装,将来只有使用–add-opens 打开特定的软件包才行。

4、JVM 优化

1、JEP 376:ZGC 并发线程处理

JEP 376 将 ZGC 线程栈处理从安全点转移到一个并发阶段,甚至在大堆上也允许在毫秒内暂停 GC 安全点。消除 ZGC 垃圾收集器中最后一个延迟源可以极大地提高应用程序的性能和效率。

2、JEP 387:弹性元空间

此特性可将未使用的 HotSpot 类元数据(即元空间,metaspace)内存更快速地返回到操作系统,从而减少元空间的占用空间。具有大量类加载和卸载活动的应用程序可能会占用大量未使用的空间。新方案将元空间内存按较小的块分配,它将未使用的元空间内存返回给操作系统来提高弹性,从而提高应用程序性能并降低内存占用。

5、新功能的预览和孵化

1、JEP 338:向量 API(孵化器)

如下内容来源于https://xie.infoq.cn/article/8304c894c4e38318d38ceb116

AVX(Advanced Vector Extensions,高级向量扩展)实际上是 x86-64 处理器上的一套 SIMD(Single Instruction Multiple Data,单指令多数据流)指令集,相对于 SISD(Single instruction, Single dat,单指令流但数据流)而言,SIMD 非常适用于 CPU 密集型场景,因为向量计算允许在同一个 CPU 时钟周期内对多组数据批量进行数据运算,执行性能非常高效,甚至从某种程度上来看,向量运算似乎更像是一种并行任务,而非像标量计算那样,在同一个 CPU 时钟周期内仅允许执行一组数据运算,存在严重的执行效率低下问题。

在这里插入图片描述

随着 Java16 的正式来临,开发人员可以在程序中使用 Vector API 来实现各种复杂的向量计算,由 JIT 编译器 Server Compiler(C2)在运行期将其编译为对应的底层 AVX 指令执行。当然,在讲解如何使用 Vector API 之前,我们首先来看一个简单的标量计算程序。示例:

void scalarComputation() {
    var a = new float[10000000];
    var b = new float[10000000];
    // 省略数组a和b的赋值操作
    var c = new float[10000000];
    for (int i = 0; i < a.length; i++) {
        c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
    }
}  

在上述程序示例中,循环体内每次只能执行一组浮点运算,总共需要执行约 1000 万次才能够获得最终的运算结果,可想而知,这样的执行效率必然低效。值得庆幸的是,从 Java6 的时代开始,Java 的设计者们就在 HotSpot 虚拟机中引入了一种被称之为 SuperWord 的自动向量优化算法,该算法缺省会将循环体内的标量计算自动优化为向量计算,以此来提升数据运算时的执行效率。当然,我们可以通过虚拟机参数-XX:-UseSuperWord来显式关闭这项优化(从实际测试结果来看,如果不开启自动向量优化,存在约 20%~22%之间的性能下降)。

在此大家需要注意,尽管 HotSpot 缺省支持自动向量优化,但局限性仍然非常明显,首先,JIT 编译器 Server Compiler(C2)仅仅只会对循环体内的代码块做向量优化,并且这样的优化也是极不可靠的;其次,对于一些复杂的向量运算,SuperWord 则显得无能为力。因此,在一些特定场景下(比如:机器学习,线性代数,密码学等),建议大家还是尽可能使用 Java16 为大家提供的 Vector API 来实现复杂的向量计算。示例:

// 定义256bit的向量浮点运算
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
void vectorComputation(float[] a, float[] b, float[] c) {
    var i = 0;
    var upperBound = SPECIES.loopBound(a.length);
    for (; i < upperBound; i += SPECIES.length()) {
        var va = FloatVector.fromArray(SPECIES, a, i);
        var vb = FloatVector.fromArray(SPECIES, b, i);
        var vc = va.mul(va).
                add(vb.mul(vb)).
                neg();
        vc.intoArray(c, i);
    }
    for (; i < a.length; i++) {
        c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
    }
}

值得注意的是,Vector API 包含在 jdk.incubator.vector 模块中,程序中如果需要使用 Vector API 则需要在 module-info.java 文件中引入该模块。:

module java16.test{
    requires jdk.incubator.vector;
} 

2、JEP 389:外部链接器 API(孵化器)

该孵化器 API 提供了静态类型、纯 Java 访问原生代码的特性,该 API 将大大简化绑定原生库的原本复杂且容易出错的过程。Java 1.1 就已通过 Java 原生接口(JNI)支持了原生方法调用,但并不好用。Java 开发人员应该能够为特定任务绑定特定的原生库。它还提供了外来函数支持,而无需任何中间的 JNI 粘合代码。

3、JEP 393:外部存储器访问 API(第三次孵化)

在 Java 14 和 Java 15 中作为孵化器 API 引入的这个 API 使 Java 程序能够安全有效地对各种外部存储器(例如本机存储器、持久性存储器、托管堆存储器等)进行操作。它提供了外部链接器 API 的基础。

如下内容来源于https://xie.infoq.cn/article/8304c894c4e38318d38ceb116

在实际的开发过程中,绝大多数的开发人员基本都不会直接与堆外内存打交道,但这并不代表你从未接触过堆外内存,像大家经常使用的诸如:RocketMQ、MapDB 等中间件产品底层实现都是基于堆外存储的,换句话说,我们几乎每天都在间接与堆外内存打交道。那么究竟为什么需要使用到堆外内存呢?简单来说,主要是出于以下 3 个方面的考虑:

  • 减少 GC 次数和降低 Stop-the-world 时间;
  • 可以扩展和使用更大的内存空间;
  • 可以省去物理内存和堆内存之间的数据复制步骤。

在 Java14 之前,如果开发人员想要操作堆外内存,通常的做法就是使用 ByteBuffer 或者 Unsafe,甚至是 JNI 等方式,但无论使用哪一种方式,均无法同时有效解决安全性和高效性等 2 个问题,并且,堆外内存的释放也是一个令人头痛的问题。以 DirectByteBuffer 为例,该对象仅仅只是一个引用,其背后还关联着一大段堆外内存,由于 DirectByteBuffer 对象实例仍然是存储在堆空间内,只有当 DirectByteBuffer 对象被 GC 回收时,其背后的堆外内存才会被进一步释放。
在这里插入图片描述

在此大家需要注意,程序中通过 ByteBuffer.allocateDirect()方法来申请物理内存资源所耗费的成本远远高于直接在 on-heap 中的操作,而且实际开发过程中还需要考虑数据结构如何设计、序列化/反序列化如何支撑等诸多难题,所以与其使用语法层面的 API 倒不如直接使用 MapDB 等开源产品来得更实惠。

如今,在堆外内存领域,我们似乎又多了一个选择,从 Java14 开始,Java 的设计者们在语法层面为大家带来了崭新的 Memory Access API,极大程度上简化了开发难度,并得以有效的解决了安全性和高效性等 2 个核心问题。示例:

// 获取内存访问var句柄
var handle = MemoryHandles.varHandle(char.class,
        ByteOrder.nativeOrder());
// 申请200字节的堆外内存
try (MemorySegment segment = MemorySegment.allocateNative(200)) {
    for (int i = 0; i < 25; i++) {
        handle.set(segment, i << 2, (char) (i + 1 + 64));
        System.out.println(handle.get(segment, i << 2));
    }
}

关于堆外内存段的释放,Memory Access API 提供有显式和隐式 2 种方式,开发人员除了可以在程序中通过 MemorySegment 的 close()方法来显式释放所申请的内存资源外,还可以注册 Cleaner 清理器来实现资源的隐式释放,后者会在 GC 确定目标内存段不再可访问时,释放与之关联的堆外内存资源。

4、JEP 397:密封类(第二预览)

封闭类可以是封闭类和或者封闭接口,用来增强 Java 编程语言,防止其他类或接口扩展或实现它们。这个特性由Java 15的预览版本晋升为正式版本。

  • 密封的类和接口解释和应用

因为我们引入了sealed classinterfaces,这些class或者interfaces只允许被指定的类或者interface进行扩展和实现。

使用修饰符sealed,您可以将一个类声明为密封类。密封的类使用reserved关键字permits列出可以直接扩展它的类。子类可以是最终的,非密封的或密封的。

之前我们的代码是这样的。

public class Person { } //人
 
class Teacher extends Person { }//教师
 
class Worker extends Person { }  //工人
 
class Student extends Person{ } //学生

但是我们现在要限制 Person类 只能被这三个类继承,不能被其他类继承,需要这么做。

// 添加sealed修饰符,permits后面跟上只能被继承的子类名称
public sealed class Person permits Teacher, Worker, Student{ } //人
 
// 子类可以被修饰为 final
final class Teacher extends Person { }//教师
 
// 子类可以被修饰为 non-sealed,此时 Worker类就成了普通类,谁都可以继承它
non-sealed class Worker extends Person { }  //工人
// 任何类都可以继承Worker
class AnyClass extends Worker{}
 
//子类可以被修饰为 sealed,同上
sealed class Student extends Person permits MiddleSchoolStudent,GraduateStudent{ } //学生
 
 
final class MiddleSchoolStudent extends Student { }  //中学生
 
final class GraduateStudent extends Student { }  //研究生

很强很实用的一个特性,可以限制类的层次结构。

6、提升 OpenJDK 开发人员的生产力

其余更改对 Java 开发人员(使用 Java 编写代码和运行应用程序的人员)不会直接可见,而只对 Java 开发人员(参与 OpenJDK 开发的人员)可见。

1、JEP 347:启用 C++14 语言特性(在 JDK 源代码中)

它允许在 JDK C++ 源代码中使用 C++14 语言特性,并提供在 HotSpot 代码中可以使用哪些特性的具体指导。在 JDK 15 中,JDK 中 C++ 代码使用的语言特性仅限于 C++98/03 语言标准。它要求更新各种平台编译器的最低可接受版本

2、JEP 357:从 Mercurial 迁移到 Git & JEP 369,迁移到 GitHub

这些 JEP 将 OpenJDK 社区的源代码存储库从 Mercurial(hg)迁移到 Git,并将它们托管在 GitHub 上以供 JDK 11 及更高版本使用,其中包括将 jcheck、webrev 和 defpath 工具等工具更新到 Git。Git 减小了元数据的大小(约 1/4),可节省本地磁盘空间并减少克隆时间。与 Mercurial 相比,现代工具链可以更好地与 Git 集成。

Open JDK Git 存储库现在位于 https://github.com/openjdk。

3、JEP 386:AlpineLinux 移植 & JEP 388:Windows/AArch64 移植

这些 JEP 的重点不是移植工作本身,而是将它们集成到 JDK 主线存储库中;JEP 386 将 JDK 移植到 Alpine Linux 和其他使用 musl 作为 x64 上主要 C 库的发行版上。此外,JEP 388 将 JDK 移植到 Windows AArch64(ARM64)。

更多内容:

更多内容大家可以关注一下个人博客网,https://blog.xueqimiao.com/,内容更丰富喔。

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

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

相关文章

特征工程资料整理,如何从数据中挖掘特征

特征工程资料整理&#xff0c;如何从数据中挖掘特征一、特征工程是什么二、探索性数据分析EDA参考资料&#xff1a;1. pandas_profiling【推荐】2. Sweetviz3. pandasgui4.D-tale【推荐】结论三、特征处理参考资料&#xff1a;1. 数值特征⭐️⭐️⭐️⭐️⭐️数值特征小结&…

用于高精度干涉仪的奇特量子效应

使用物质波放大、跟踪加速度&#xff0c;以前从未以便携式形式实现。&#xff08;图片来源&#xff1a;网络&#xff09; 来自法国的一组研究人员开发了第一个三向混合量子惯性传感器&#xff0c;它可以在不使用卫星信号的情况下测量加速度。这个突破性设备的核心是“物质波干涉…

传统目标跟踪——MeanShift算法

目录 一、均值漂移&#xff08;MeanShift&#xff09; 二、流程 三、代码 3.1 meanshift&#xff0b;固定框的代码 3.2 优化&#xff1a;meanshift鼠标选择 3.3 meanshift自己实现函数 四、补充知识 4.1 直方图 4.2 归一化 4.3 直方图反投影 一、均值漂移&#xff08;…

Maven 教程

Maven 教程 Maven 翻译为"专家"、“内行”&#xff0c;是 Apache 下的一个纯 Java 开发的开源项目。基于项目对象模型&#xff08;缩写&#xff1a;POM&#xff09;概念&#xff0c;Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。 Maven 是一…

手把手教你阿里云服务器的购买及环境搭建

1.服务器相关 程序员都需要一个自己的服务器! 用于发布自己的网站和项目&#xff01;用于操作系统的练习&#xff01;将自己的远程仓库、远程数据库、远程tomcat… 搭建在服务器上&#xff01;用于Linux进行任意的环境部署操作&#xff01; 服务器如何购买 若果你没超过24岁&am…

【Bp2Lua】多返回值和Out参数说明

【Bp2Lua】多返回值和Out参数说明 这块比较繁琐&#xff0c;有四部分需要了解&#xff1a; U蓝图LuaUnLua 最后再解释 Bp2Lua 如何处理&#xff0c;以及后续潜在的风险 Bp2Lua 如何处理 先说结论 统一当作多返回值返回特殊处理了 out参数 不在参数列表最后的情况&#xf…

分布式理论之分布式锁

写在前面 在分布式理论之分布式互斥 一文中我们分析了分布式环境中的分布式互斥问题,其中解决该问题有如下的三种方案&#xff1a; 1&#xff1a;集中式算法 2&#xff1a;分布式算法 3&#xff1a;令牌环算法而本文要分析的分布式锁&#xff0c;就是其中的算法1&#xff0c;…

折腾了我一周,原来Netty网络编程就是这么个破玩意儿!!!

1、阻塞 阻塞模式下&#xff0c;相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停SocketChannel.read 会在通道中没有数据可读时让线程暂停阻塞的表现其实就是线程暂停了&#xff0c;暂停期间不会占用 cpu&#xff0c;但线程相当于闲置 单线…

flowable学习笔记(四):动态多实例

1.定义流程模板 【测试用户任务多实例】任务节点配置了以下属性&#xff1a; 集合(多实例)&#xff1a;userList。这个创建流程实例时入参需要加上这个参数。 元素变量(多实例)&#xff1a;user。工作流创建多实例时会将集合(多实例)的值拆分成元素变量(多实例)&#xff0c;这个…

Git复习,GitHub\Gitee的使用,IDEA集成Git

今天想把自己的课设上传到GitHub&#xff0c;因为长久不用&#xff0c;Git的命令忘得差不多了&#xff0c;所以今天把Git重新学一遍。 文章目录Git的介绍Git的安装Git的常用命令工作机制常用命令用户签名初始化本地库查看本地库状态添加暂存区提交本地库查看引用日志信息修改文…

Python常用函数笔记汇总2

1.分组汇总groupby 2.计算空值 # py计算空值 data.isnull().sum(axis0) data.notnull().sum(axis0)# py去重计数 data_op[id_num_op].value_counts().size data_op[id_num_op].size3.保留两位小数 # predict_proba保留两位小数 gnb GaussianNB() pre gnb.fit(X_train,y_tr…

pytest-日志配置

如果想要在run测试用例时&#xff0c;打印出由python的logging的日志&#xff0c;可以在pytest中进行相应的配置 pytest可以将日志输出到控制台或者文件中&#xff0c;分别对应不同的配置项 pytest的日志配置文件主要在pytest.ini文件中进行配置&#xff0c;包括配置日志的格式…

ARM64内存虚拟化分析(5)内存布局更新

1 添加MR 创建的MR需要通过函数memory_region_add_subregion()添加到系统中&#xff0c;提交MR&#xff0c;并最终往KVM提交内存的变化。 过程如下&#xff1a; 将mr设置为subregion的container&#xff1b;设置subregion在虚拟机中的物理地址&#xff1b;调用memory_region_t…

FOHEART H1数据手套_Unity3D SDK开发

本教程介绍使用FOHEART H1数据手套在Unity3D中&#xff0c;显示每段骨骼的位置与旋转信息。 需要准备的软硬件&#xff1a; 1、FOHEART H1数据手套 2、MotionVenus客户端 3、Unity3D软件 4、开发包MotionVenus_U3DPlugin_v2.0_H1GloveDev_SDKTest.unitypackage 1、连接数…

HFSS学习笔记

以下所有操作&#xff0c;都是基于2022版本的HFSS。一、HFSS solution模式选择位置&#xff1a;HFSS-Solution type类型表格。二、单位设置位置&#xff1a;Modeler-Units点击后&#xff0c;通常选用单位为&#xff1a;mm三、绘制物体点击红圈1的draw&#xff0c;右侧有些形状可…

MCU-51:单片机实时时钟

目录一、什么是时钟1.1 实时时钟1.2 时序二、DS1302实时时钟2.1 DS1302介绍2.2 引脚定义和应用电路三、代码演示3.1 数字时钟3.2 DS1302可调时钟注意&#xff1a;一定要看一、什么是时钟 1.1 实时时钟 real time clock&#xff0c;真实时间&#xff0c;就是所谓的xx年x月x日x…

我的统计学学习笔记(持续更新)

目录数据&#xff1a;变量和观测统计学描述统计数据的收集数据的可视化数据的规律性特征统计推断参数估计假设检验贝叶斯统计基础知识&#xff1a;概率论数据&#xff1a;变量和观测 变量(column)、观测(row)、测量(assign number to observation)。 统计学 描述统计 数据…

YOLO-V5 系列算法和代码解析(四)—— 网络结构

文章目录辅助工具网络配置文件网络构建网络推理绘制网络结构辅助工具 借助辅助工具可视化网络结构&#xff0c;达到辅助阅读代码&#xff0c;进而辅助手动绘制结构清晰的网络结构&#xff0c;最终理解整个网络架构的目的&#xff0c;为深入学习【yolo-v5】提供有效的保障。 ten…

阿里妈妈内容风控模型预估引擎的探索和建设

作者&#xff1a;徐雄飞、金禄旸、滑庆波、李治 内容作为营销的重要载体&#xff0c;能够促进信息的交流和传播。在营销场景中&#xff0c;广告高曝光的特性放大了风险外漏带来的一系列问题&#xff0c;因此对内容的风控审核就显得至关重要。本文将为大家分享阿里妈妈内容风控模…

DOM节点操作

节点操作 改变元素节点中的内容可以使用两个相关属性&#xff1a;innerHTML innerText 注意字符串不能换行 innerHTML属性能以HTML语法设置节点中的内容 innerText属性只能以纯文本的形式设置节点中的内容 节点创建 document.createElement()方法用于创建一个指定tagname…