Java 比较器解析

一、比较器的核心作用与应用场景

在 Java 编程中,数据比较是一个基础但重要的操作。对于基本数据类型(如 int、double、boolean、char 等),Java 语言本身就提供了完整的比较运算符(>、<、==、>=、<=、!=)可以直接使用。例如:

int a = 10;
int b = 20;
boolean result = a < b; // 返回 true

然而,当涉及到自定义对象(即开发者定义的类实例)时,情况就完全不同了。假设我们有一个 Student 类:

class Student {private String name;private int score;// 构造方法和其他方法...
}

如果我们尝试直接比较两个 Student 对象:

Student s1 = new Student("Alice", 90);
Student s2 = new Student("Bob", 85);
boolean comp = s1 > s2; // 编译错误!无法直接比较对象

这时就需要比较器来发挥作用。比较器的核心作用就是为自定义对象定义明确的比较规则,使得这些对象能够按照开发者的预期进行排序或比较。Java 提供了两种主要的比较方式:

  1. Comparable 接口:让对象自身实现比较逻辑
  2. Comparator 接口:定义独立于对象的比较逻辑

比较器在实际开发中有广泛的应用场景,主要包括:

  1. 集合排序

    • 对 List、Set 等集合中的自定义对象进行排序
    • 例如:对学生列表按成绩从高到低排序
    • 使用 Collections.sort() 或 List.sort() 方法
  2. 优先级队列

    • 实现基于自定义规则的优先级队列(PriorityQueue)
    • 例如:急诊系统中的患者优先队列
  3. Stream 操作

    • 在 Stream 流操作中使用 sorted() 方法进行排序
    • 例如:从数据库查询出的数据流按特定字段排序
  4. 有序集合

    • 实现具有自定义排序规则的数据结构
    • 如 TreeMap(基于键的排序)、TreeSet 等
    • 例如:按员工工号排序的员工信息映射表
  5. 算法实现

    • 在需要比较操作的算法中使用,如二分查找、排序算法等

比较器的使用使得对象间的比较和排序变得灵活且可控,开发者可以根据业务需求定义任意的比较规则,比如按多个字段组合排序、按逆序排序等。这种机制是 Java 集合框架强大功能的重要支撑之一。

二、Comparable 接口:对象自身的比较能力

Comparable接口位于java.lang包下,是一个泛型接口,其定义如下:

public interface Comparable<T> {public int compareTo(T o);
}

2.1 核心方法解析

compareTo(T o)方法是Comparable接口中唯一的抽象方法,它的作用是将当前对象与参数对象o进行比较,返回一个整数值,具体含义如下:

  • 返回正整数:表示当前对象大于参数对象
  • 返回0:表示当前对象等于参数对象
  • 返回负整数:表示当前对象小于参数对象

该方法需要满足以下数学特性:

  1. 自反性:x.compareTo(x) == 0
  2. 对称性:x.compareTo(y)与y.compareTo(x)符号相反
  3. 传递性:如果x.compareTo(y) > 0且y.compareTo(z) > 0,则x.compareTo(z) > 0

2.2 使用示例:自定义对象实现 Comparable

下面以Student类为例,演示如何实现Comparable接口:

public class Student implements Comparable<Student> {private String name;private int age;private double score;// 构造方法public Student(String name, int age, double score) {this.name = name;this.age = age;this.score = score;}// getter和setter方法public String getName() { return name; }public int getAge() { return age; }public double getScore() { return score; }@Overridepublic int compareTo(Student o) {// 按照年龄升序排序return Integer.compare(this.age, o.age);// 如果需要降序排序,可以改为:// return Integer.compare(o.age, this.age);// 注意:直接使用减法(this.age - o.age)可能导致整数溢出问题}
}

实现Comparable接口后,我们就可以使用Collections.sort()或Arrays.sort()方法对对象数组或集合进行排序:

public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("张三", 20, 85.5));students.add(new Student("李四", 18, 90.0));students.add(new Student("王五", 22, 78.5));students.add(new Student("赵六", 19, 88.0));// 直接调用sort方法,会使用Student类自身实现的compareTo方法Collections.sort(students);System.out.println("按年龄排序结果:");for (Student s : students) {System.out.printf("%s - 年龄:%d,分数:%.1f%n", s.getName(), s.getAge(), s.getScore());}
}

2.3 Comparable 的特点与局限性

特点:
  1. 自然排序:实现Comparable接口的类具有自身比较能力,可以直接进行排序
  2. 内置规则:排序规则是固定的,属于类的一部分
  3. 实现简单:只需重写compareTo方法
  4. 广泛支持:可以被标准集合类(如TreeSet、TreeMap)直接使用
局限性:
  1. 排序规则固定:无法在运行时动态改变比较逻辑
  2. 修改受限:如果类已经被定义且无法修改(如第三方类库中的类),则无法实现Comparable接口
  3. 单一规则:只能实现一种排序规则,无法满足多种排序需求(如需同时支持按年龄和分数排序)
  4. 侵入性强:需要修改类本身,可能违反开闭原则
替代方案:

当Comparable不能满足需求时,可以考虑使用Comparator接口,它允许在不修改原有类的情况下定义多种比较规则。

三、Comparator 接口:外部比较器

1. 接口概述

Comparator 接口位于 java.util 包下,是一个泛型接口,也是 Java 函数式编程的重要接口之一。其核心定义如下:

@FunctionalInterface
public interface Comparator<T> {int compare(T o1, T o2);// 其他默认方法和静态方法省略
}

2. 核心方法解析

compare(T o1, T o2) 方法是 Comparator 接口的核心方法,用于比较两个参数对象的大小,返回值含义如下:

  • 返回正整数:表示 o1 大于 o2
  • 返回0:表示 o1 等于 o2
  • 返回负整数:表示 o1 小于 o2

这个方法遵循了反自反性对称性传递性的数学比较规则,确保排序的一致性。

3. 使用方式

3.1 自定义类实现 Comparator 接口

这是最传统的方式,适合需要重复使用的比较逻辑。

// 按照学生年龄升序排序的比较器
public class AgeAscComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge();}
}// 按照学生成绩降序排序的比较器
public class ScoreDescComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {// 注意:double类型不建议直接相减,可能存在精度问题return Double.compare(o2.getScore(), o1.getScore());}
}

使用时,将比较器作为参数传递给排序方法:

public static void main(String[] args) {List<Student> students = new ArrayList<>();// 添加元素...students.add(new Student("Alice", 20, 88.5));students.add(new Student("Bob", 19, 92.0));students.add(new Student("Charlie", 21, 85.5));// 使用年龄升序比较器Collections.sort(students, new AgeAscComparator());// 使用成绩降序比较器Collections.sort(students, new ScoreDescComparator());
}

3.2 匿名内部类形式

对于简单的比较逻辑,可以使用匿名内部类,避免创建过多的比较器类:

// 按照姓名升序排序(字典顺序)
Collections.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getName().compareTo(o2.getName());}
});// 按照学生ID排序
Collections.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return Long.compare(o1.getId(), o2.getId());}
});

3.3 Lambda 表达式形式(Java 8+)

由于 Comparator 是函数式接口,在 Java 8 及以上版本中,可以使用 Lambda 表达式简化代码:

// 按照年龄降序排序
Collections.sort(students, (s1, s2) -> s2.getAge() - s1.getAge());// 按照成绩升序排序
students.sort((s1, s2) -> Double.compare(s1.getScore(), s2.getScore()));// 更简洁的写法:使用方法引用
students.sort(Comparator.comparingInt(Student::getAge));

4. Comparator 的默认方法与链式比较

Java 8 为 Comparator 接口增加了多个默认方法,使得比较器的使用更加灵活,可以实现链式比较。

4.1 常用默认方法

  • reversed():返回一个反向的比较器
  • thenComparing(Comparator):当前比较器比较结果相等时,使用参数比较器继续比较
  • thenComparingInt(ToIntFunction):针对 int 类型的属性进行二次比较
  • thenComparingLong(ToLongFunction):针对 long 类型的属性进行二次比较
  • thenComparingDouble(ToDoubleFunction):针对 double 类型的属性进行二次比较

4.2 链式比较示例

// 复杂排序:先按年龄升序,年龄相同按成绩降序,成绩相同按姓名升序
Comparator<Student> complexComparator = Comparator.comparingInt(Student::getAge).thenComparing(Student::getScore, Comparator.reverseOrder()).thenComparing(Student::getName);students.sort(complexComparator);

4.3 实用静态方法

Comparator 接口还提供了一些实用的静态方法:

// 处理null值的情况:null元素排在最后
Comparator.nullsLast(Comparator.comparing(Student::getName));// 自然顺序比较
Comparator.naturalOrder();// 反向自然顺序
Comparator.reverseOrder();

5. 实际应用场景

  1. 集合排序:对 List 进行多种规则的排序
  2. 优先队列:自定义优先级队列的排序规则
  3. TreeMap/TreeSet:自定义排序规则的集合
  4. Stream API:在流式操作中进行排序
  5. 数据库查询结果排序:对查询结果进行内存排序

6. 注意事项

  1. 对于浮点数比较,建议使用 Double.compare()Float.compare() 而非直接相减
  2. 比较器应确保满足比较的数学性质(自反性、对称性、传递性)
  3. 对于可能为null的对象,考虑使用 Comparator.nullsFirst()Comparator.nullsLast()
  4. 在多线程环境下,比较器应该是线程安全的(通常是无状态的)

通过合理使用 Comparator 接口及其丰富的方法,可以实现各种复杂的排序需求,使代码更加简洁和灵活。

四、Comparable 与 Comparator 的区别与联系

特性

Comparable

Comparator

所在包

java.lang

java.util

方法名称

compareTo(T o)

compare(T o1, T o2)

比较方式

自身与其他对象比较

两个外部对象比较

实现位置

被比较的类内部

被比较的类外部

灵活性

固定排序规则,灵活性低

可定义多个比较器,灵活性高

适用场景

类的默认排序规则

动态改变排序规则或第三方类排序

联系

  • 两者都是用于定义对象之间的比较规则
  • 都返回 int 类型的比较结果
  • 都可以用于集合或数组的排序操作

五、比较器的底层排序原理

Java 中的排序算法会根据不同的场景选择合适的排序实现。在基础数据类型的排序中,Java 会使用针对特定数据类型优化的排序算法,如对int数组使用Dual-Pivot Quicksort(双轴快速排序)。而对于对象数组或集合的排序,主要使用TimSort算法(Java 7 及以上版本),这是一种结合了归并排序和插入排序的混合排序算法,具有以下特点:

  1. 时间复杂度:最坏情况O(n log n),最好情况O(n)
  2. 稳定排序:能够保持相等元素的原始相对顺序
  3. 对小规模数据会自动切换到插入排序

比较器在排序过程中的作用是提供灵活的比较规则,排序算法会根据比较器返回的结果来决定元素的位置。具体来说,排序过程会经历以下步骤:

  1. 当调用Arrays.sort()或Collections.sort()方法时
  2. 排序算法会初始化比较器实例
  3. 在排序过程中,会多次调用比较器的compareTo或compare方法
  4. 根据返回值(负值、零、正值)判断元素的相对顺序
    • 负值表示第一个参数小于第二个
    • 零表示相等
    • 正值表示第一个参数大于第二个
  5. 通过不断比较和交换元素位置,直到整个集合有序

应用示例:

List<Person> persons = new ArrayList<>();
// 添加元素...
Collections.sort(persons, (p1, p2) -> {// 先按年龄排序int ageCompare = Integer.compare(p1.getAge(), p2.getAge());if (ageCompare != 0) return ageCompare;// 年龄相同则按姓名排序return p1.getName().compareTo(p2.getName());
});

六、使用比较器的注意事项

6.1 避免整数溢出问题

当使用整数类型(如 int)的差值作为比较结果时,可能会出现整数溢出问题,尤其是在处理接近边界值的情况时:

// 错误示例:可能导致溢出
@Override
public int compareTo(Student o) {// 当this.age为Integer.MAX_VALUE(2147483647),o.age为负数(如-1)时// 2147483647 - (-1) = 2147483648,超出int范围导致溢出为-2147483648return this.age - o.age;
}// 正确示例:使用Integer.compare方法
@Override
public int compareTo(Student o) {// Integer.compare内部安全处理了边界情况return Integer.compare(this.age, o.age);
}

同样,对于 long 类型:

// 使用Long.compare
return Long.compare(this.bigNumber, o.bigNumber);

对于 double 类型:

// 使用Double.compare
return Double.compare(this.precisionValue, o.precisionValue);

6.2 保持比较的一致性

比较器的实现必须满足以下数学性质,否则可能导致排序结果不稳定或出现异常:

  1. 自反性:compare(a, a)必须返回 0

    • 例:比较两个相同对象时总返回0
  2. 对称性:compare(a, b)与compare(b, a)的结果必须相反

    • 例:若compare("a","b")返回-1,则compare("b","a")应返回1
  3. 传递性:如果compare(a, b) < 0且compare(b, c) < 0,则compare(a, c) < 0

    • 例:若a < b且b < c,则必须保证a < c

6.3 注意空值处理

当比较的对象可能为 null 时,需要明确null的处理策略:

// 处理可能为null的情况
Comparator<Student> comparator = (s1, s2) -> {if (s1 == s2) return 0; // 包括两个都为null的情况if (s1 == null) return -1; // 定义null小于任何非null值if (s2 == null) return 1;  // 定义非null值大于nullreturn s1.getName().compareTo(s2.getName()); // 都不为null时比较name
};// 另一种处理方式:使用nullsFirst/nullLast
Comparator<Student> nullSafeComparator = Comparator.nullsFirst(Comparator.comparing(Student::getName));

6.4 注意浮点类型的比较

浮点类型直接相减比较可能存在精度问题:

// 错误示例:可能存在精度问题
return (int)(this.score - o.score); // 可能丢失精度且仍可能溢出// 正确示例:使用Double.compare方法
return Double.compare(this.score, o.score); // 正确处理NaN和精度问题// 如果需要指定精度范围比较
private static final double EPSILON = 0.0001;
public int compareWithTolerance(Double a, Double b) {if (Math.abs(a - b) < EPSILON) {return 0;}return Double.compare(a, b);
}

6.5 考虑排序的稳定性

稳定的排序算法在比较相等元素时能保持原始顺序:

List<Student> students = ...;// 多级比较保证稳定性
students.sort(Comparator.comparingInt(Student::getAge)      // 主排序字段.thenComparing(Student::getName)   // 次排序字段.thenComparingInt(Student::getId)); // 唯一标识字段// 实际应用场景:先按部门排序,部门相同的按入职时间排序
employees.sort(Comparator.comparing(Employee::getDepartment).thenComparing(Employee::getHireDate));

七、实际开发中的最佳实践

7.1 优先使用 Comparator 接口

在 Java 集合排序中,建议优先使用 Comparator 接口而非 Comparable 接口,因为 Comparator 提供了更灵活的排序方案:

  1. 多排序规则支持:可以为同一个类定义多个比较器,实现不同的排序规则。例如,对 Student 类可以分别按年龄、成绩或姓名排序:

    Comparator<Student> byAge = Comparator.comparingInt(Student::getAge);
    Comparator<Student> byScore = Comparator.comparingDouble(Student::getScore);
    Comparator<Student> byName = Comparator.comparing(Student::getName);
    

  2. 非侵入式排序:不需要修改被比较类的源代码,特别适合对第三方库中的类进行排序。例如对 String 类进行自定义排序:

    Comparator<String> lengthComparator = Comparator.comparingInt(String::length);
    

  3. 运行时灵活性:可以在运行时根据业务需求动态选择排序规则。例如:

    Comparator<Student> currentComparator = userPrefersAgeSorting ? byAge : byScore;
    

  4. 链式比较:支持多级排序,当第一个比较条件相等时,可以继续使用其他比较条件:

    Comparator<Student> complexComparator = byAge.thenComparing(byScore).thenComparing(byName);
    

7.2 结合 Stream API 使用

Java 8 引入的 Stream API 与 Comparator 完美配合,可以优雅地实现集合排序:

  1. 基本排序示例

    List<Student> students = getStudents();
    List<Student> sortedStudents = students.stream().sorted(Comparator.comparingInt(Student::getAge))  // 按年龄升序.collect(Collectors.toList());
    

  2. 降序排序

    List<Student> reversedSorted = students.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).collect(Collectors.toList());
    

  3. 多字段排序

    List<Student> multiSorted = students.stream().sorted(Comparator.comparing(Student::getGrade).thenComparing(Student::getScore).reversed()).collect(Collectors.toList());
    

  4. 空值处理

    // 将null值排在最后
    Comparator<Student> nullsLast = Comparator.nullsLast(Comparator.comparing(Student::getName));
    

7.3 为常用比较器提供静态工厂方法

在业务类中提供静态工厂方法可以增强代码的可读性和复用性:

public class Student {private String name;private int age;private double score;// 构造方法、getter/setter省略.../*** 创建按年龄升序的比较器*/public static Comparator<Student> ageAscComparator() {return Comparator.comparingInt(Student::getAge);}/*** 创建按成绩降序的比较器*/public static Comparator<Student> scoreDescComparator() {return Comparator.comparingDouble(Student::getScore).reversed();}/*** 创建先按班级后按姓名的比较器*/public static Comparator<Student> classThenNameComparator() {return Comparator.comparing(Student::getClassName).thenComparing(Student::getName);}
}// 使用示例
List<Student> students = getStudents();
students.sort(Student.ageAscComparator());
// 或者
students.sort(Student.scoreDescComparator());

这种模式的优点:

  • 将比较逻辑封装在被比较类中,符合封装原则
  • 方法名可以清晰地表达比较规则
  • 避免在业务代码中重复编写比较逻辑
  • 便于统一修改比较规则

7.4 使用 Comparator.comparing 简化代码

Java 8 的 Comparator 类提供了一系列静态工厂方法,可以极大简化比较器的创建:

  1. 基本比较方法

    // 按姓名排序(区分大小写)
    Comparator<Student> byName = Comparator.comparing(Student::getName);// 按年龄排序
    Comparator<Student> byAge = Comparator.comparingInt(Student::getAge);// 按成绩排序
    Comparator<Student> byScore = Comparator.comparingDouble(Student::getScore);
    

  2. 自定义键提取器

    // 按姓名长度排序
    Comparator<Student> byNameLength = Comparator.comparing(student -> student.getName().length());
    

  3. 链式比较

    // 先按年级,再按年龄,最后按成绩
    Comparator<Student> complexComparator = Comparator.comparing(Student::getGrade).thenComparing(Student::getAge).thenComparingDouble(Student::getScore);
    

  4. 空值安全比较

    // 处理可能为null的属性
    Comparator<Student> nullSafeComparator = Comparator.comparing(Student::getName, Comparator.nullsLast(Comparator.naturalOrder()));
    

  5. 自定义比较器

    // 使用自定义的字符串比较规则
    Comparator<Student> caseInsensitive = Comparator.comparing(Student::getName, String.CASE_INSENSITIVE_ORDER);
    

这些方法不仅使代码更简洁,还能提高可读性和维护性,是现代化Java编程中处理排序的首选方式。

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

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

相关文章

Java学习第一百二十一部分——HTTP

目录 一、前言简介 二、核心特性 三、通信基础结构 四、关键组件详解 五、性能演进——版本对比 六、开发者建议 七、总结归纳 一、前言简介 HTTP&#xff08;“H”yper“t”ext “T”ransfer “P”rotocol&#xff0c;超文本传输协议&#xff09;是互联网上应用最广泛…

记录RK3588的docker中启动rviz2报错

安装好rk3588 的docker&#xff0c;pull了ros的完整镜像后&#xff0c;想要启动rviz但是报错&#xff0c;下面是我的踩坑记录 0.原始的启动镜像的脚本&#xff1a; sudo docker run -it --rm --privileged --nethost -e DISPLAY$DISPLAY --namemy_image_name \-e DISPLAY$DIS…

ThingJS 新手学习技巧

一、ThingJS 基础认知 1.1 ThingJS 是什么 ThingJS 是一款基于 WebGL 技术的 3D 可视化开发平台&#xff0c;它为开发者提供了简单易用的 API 和丰富的 3D 场景组件&#xff0c;让开发者能够快速构建出高质量的 3D 可视化应用。无论是智慧园区、智慧楼宇、智慧交通还是工业监…

【软考架构】需求工程中,系统分析与设计的结构化方法

结构化方法诞生于20世纪70年代&#xff0c;是为了应对当时日益复杂的软件系统开发挑战&#xff08;如“软件危机”&#xff09;而提出的。它强调系统性、规范性、分解和抽象&#xff0c;目标是提高软件开发的效率、质量和可维护性&#xff0c;降低复杂性。 核心思想&#xff1a…

FPGA常用资源之IO概述

目录 一、前言 二、I/O资源 2.1 I/O端口资源 2.1.1 IOB 2.1.2 ILOGIC/OLOGIC 2.2 ZHOLD 2.3 IDDR/ODDR 2.4 IDELAY 2.5 ISERDES/OSERDES 2.6 IO Logic Resource连接 2.7 Device示意图 三、工程示例 3.1 工程代码 3.2 Device结果 一、前言 FPGA芯片从内部结构看主…

密集遮挡场景识别率↑31%!陌讯轻量化部署方案在智慧零售的实战解析

一、零售业痛点&#xff1a;当技术遇上客流洪流据《2024智慧零售技术白皮书》统计&#xff0c;高峰期超市顾客密度超3人/㎡时&#xff0c;​​目标漏检率高达48%​​。核心挑战包括&#xff1a;​​动态遮挡​​&#xff1a;购物车/货架造成的持续性目标截断​​计算瓶颈​​&a…

力扣(O(1) 时间插入、删除和获取随机元素)

一、题目分析&#xff08;一&#xff09;功能需求 我们需要实现 RandomizedSet 类&#xff0c;包含以下功能&#xff1a; RandomizedSet()&#xff1a;初始化数据结构。bool insert(int val)&#xff1a;当元素 val 不存在时&#xff0c;插入该元素并返回 true&#xff1b;若已…

前端开发的面试自我介绍与准备

前端面试自我介绍不知道怎么说的&#xff0c;直接参考下面的模板&#xff0c;然后换成你的经历 自我介绍控制在1分钟左右&#xff0c;千万不要说的太久&#xff0c;面试官会烦的&#xff0c;但是又不好意思打断你 切记面试是人和人面对面的交流&#xff0c;要有&#xff0c;面试…

10、系统规划与分析

一、系统规划步骤系统规划步骤对现有系统进行初步调查分析和确定系统目标分析子系统的组成和基本功能拟定系统的实施方案拟定系统的可行性研究指定系统建设方案系统规划阶段的产出物&#xff1a;可行性研究报告、系统设计任务书。习题1、拟定系统的实施方案是在系统规划阶段完成…

Nginx学习笔记(六)—— Nginx反向代理

&#x1f4da;Nginx学习笔记&#xff08;六&#xff09;—— Nginx反向代理 &#x1f4cc; 一、反向代理核心概念 本质原理&#xff1a; #mermaid-svg-UkFRDp2Ut7MK5T2N {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-s…

三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片

三伍微电子GSR2406 IoT FEM 2.4G PA 射频前端模组芯片规格书Product Description The GSR2406 is a high-performance, fully integrated RF front-end module (FEM) designed for Zigbee technology, Thread, and Bluetooth (including low energy) applications. The GSR2406…

开发避坑指南(24):RocketMQ磁盘空间告急异常处理,CODE 14 “service not available“解决方案

异常信息 Caused by: org.apache.rocketmq.client.exception.MQBrokerException: CODE: 14 DESC: service not available now, maybe disk full, CL: 0.94 CQ: 0.94 INDEX: 0.94, maybe your broker machine memory too small.异常背景 一个项目里面用到了rocketmq&#x…

开源WAF新标杆:雷池SafeLine用语义分析重构网站安全边界

文章目录前言【视频教程】1.安装Docker2.本地部署SafeLine3.使用SafeLine4.cpolar内网穿透工具安装5.创建远程连接公网地址6.固定Uptime Kuma公网地址前言 当个人或企业站点上线后面临的首要威胁往往来自网络攻击——据统计&#xff0c;超过60%的Web应用漏洞利用尝试在流量到达…

Mac M1探索AnythingLLM+SearXNG

SearXNG 能聚合来自多达 200 多个搜索服务&#xff0c;可私有化部署&#xff0c;并提供了灵活自定义选项。 AnythingLLMSearXNG&#xff0c;刚好能解决AnythingLLM因为网络限制导致web search不可用的问题。 1 安装docker 下载mac m1版本的docker并安装。 https://docs.dock…

模式设计:策略模式及其应用场景

简介 策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时动态选择算法或行为。核心思想是将算法封装成独立的类(策略),使它们可以相互替换,让算法的变化独立于使用它的客户端。 核心思想 解耦:将算法的定义与使用分离。每个算法封装起来,使它们可以互…

Squash Merge(压缩合并)和Rebase Merge(变基合并)介绍

文章目录**1. Squash Merge&#xff08;压缩合并&#xff09;****定义****操作步骤****特点****优点****缺点****2. Rebase Merge&#xff08;变基合并&#xff09;****定义****操作步骤****特点****优点****缺点****3. 对比总结****4. 选择建议****5. 示例场景****Squash Merg…

Linux编程 —— framebuffer

一、framebuffer概念framebuffer&#xff1a;帧缓冲&#xff0c;帧缓存技术Linux内核专门为图形化显示提供的一套应用程序接口。二、基本操作步骤1. 打开显示设备(/dev/fb0) 2. 获取显示设备相关参数&#xff08;分辨率&#xff0c;像素格式&#xff09;---》ioctl 3. 建立显存…

文件编辑html

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>文件行内容编辑器</title><script src&…

具有熔断能力和活性探测的服务负载均衡解决方案

一、整体架构设计 1.核心组件 负载均衡器&#xff1a;负责选择可用的服务节点健康检查器&#xff1a;定期检测服务节点的可用性服务节点管理&#xff1a;维护所有可用节点的状态信息 2.负载均衡策略 轮询(Round Robin)随机(Random)加权轮询(Weighted Round Robin)最少连接(Leas…

技术演进中的开发沉思-62 DELPHI VCL系列:VCL下的设计模式

今天聊聊设计模式&#xff0c;当然这个章节目前仅限于DELPHI VCL,因为接下来梳理的Factory/Factory Method、Bootstrap 和 ForEach 这三种设计样例&#xff0c;看似独立&#xff0c;却在实际开发中相互配合&#xff0c;共同构建起高效、灵活的程序架构。在 DELPHI VCL 开发的技…