kotlin的密封类

引言

密封类是一种特殊的类,它用来表示受限的类继承结构,即一个类只能有有限的几种子类,而不能有任何其他类型的子类。

这不就是JAVA的枚举么。

概念

密封类使用sealed关键字声明,

在Kotlin 1.0中,密封类的所有子类必须嵌套在密封类内部;

在Kotlin 1.1中,这个限制放宽了,允许将子类定义在同一个文件中;

在Kotlin 1.5中,这个限制进一步放宽了,允许将子类定义在任何地方,只要保证子类可见性不高于父类。

密封类通常用于代替枚举类。密封类的优点在于可以更灵活地定义子类,而枚举类的每个成员都是固定的。密封类还可以帮助你编写更加类型安全的代码

密封类最大的优点是可以配合when表达式实现完备性检查(exhaustive check),即编译器可以检测出是否覆盖了所有可能的分支情况,如果没有则会报错或提示警告。这样可以避免遗漏某些情况导致逻辑错误或运行时异常。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

很抽象。

密封类和枚举的区别是什么?

相同点:所有成员都属于本类本身

不同点:枚举只能有一个实例,而密封类的子类可以有多个实例。

密封类的子类可以携带自己独有的状态参数以及行为方法来记录更多的实现信息以完成更多的功能,这是枚举类所不具备的。

例子:

sealed class MyScore {
 
    object FAIL_A_GRADE : MyScore()//分数差
    object PASS_THE_MARK : MyScore()//分数及格
    object SCORE_WELL : MyScore()//分数良好
    class EXCELLENT_MARKS(val name: String) : MyScore()//分数优秀
 
}

密封类的所有成员都继承本类MyScore ,但是允许个别成员拥有自己特殊属性如 EXCELLENT_MARKS 。

三、使用

密封类的代数数据类型

密封类与 when结合,使用 is 进行判断类型,跟枚举类相似

fun show() = when (myScore) {
        is MyScore.FAIL_A_GRADE -> "分数差"
        is MyScore.PASS_THE_MARK -> "分数及格"
        is MyScore.SCORE_WELL -> "分数良好"
        is MyScore.EXCELLENT_MARKS -> "分数优秀,name=${myScore.name}"
        
    }

密封类实例

当某个成员需要特殊属性的时候,用枚举就比较难实现这个需求,密封类就是为了解决这个问题而出现的。

如下实例:当我们想知道优秀学生的名字的时候,只用枚举去实现就不好实现

//密封类,所有成员都继承本类
//当某个成员需要特殊属性的时候,用枚举就比较难实现这个需求
sealed class MyScore {
 
    object FAIL_A_GRADE : MyScore()//分数差
    object PASS_THE_MARK : MyScore()//分数及格
    object SCORE_WELL : MyScore()//分数良好
    class EXCELLENT_MARKS(val name: String) : MyScore()//分数优秀
 
}
 
 
class Teachers(private val myScore: MyScore) {
 
    fun show() = when (myScore) {
 
        is MyScore.FAIL_A_GRADE -> "分数差"
        is MyScore.PASS_THE_MARK -> "分数及格"
        is MyScore.SCORE_WELL -> "分数良好"
        is MyScore.EXCELLENT_MARKS -> "分数优秀,name=${myScore.name}"
 
    }
 
}
 
//todo kotlin语言的密封类学习
fun main() {
    println(Teachers(MyScore.FAIL_A_GRADE).show())
    println(Teachers(MyScore.EXCELLENT_MARKS("kotlin")).show())
 
}

输出:

分数差
分数优秀,name=kotlin

四、密封类与设计模式

1.状态模式

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。状态模式将状态封装成独立的类,并将请求委托给当前的状态对象,从而实现状态的切换和行为的变化。

1.1kotlin实现

密封类可以表示一个有限的状态集合,而且可以在when表达式中进行完备的检查,不需要使用else分支。例如,假设有一个电灯类,它有两种状态:开和关,每种状态下可以执行不同的操作。可以用以下的代码来实现:

// 定义一个密封类表示状态
sealed class State {
    // 定义一个抽象方法表示操作
    abstract fun operate()
}

// 定义一个开状态的子类,继承自State
class On : State() {
    // 重写操作方法,打印信息并切换到关状态
    override fun operate() {
        println("The light is on, turn it off.")
        Light.state = Off()
    }
}

// 定义一个关状态的子类,继承自State
class Off : State() {
    // 重写操作方法,打印信息并切换到开状态
    override fun operate() {
        println("The light is off, turn it on.")
        Light.state = On()
    }
}

// 定义一个电灯类,它有一个状态属性,初始为关状态
object Light {
    var state: State = Off()

    // 定义一个方法,根据当前状态执行操作
    fun switch() {
        state.operate()
    }
}

// 测试代码
fun main() {
    // 创建一个电灯对象
    val light = Light
    // 调用switch方法,根据当前状态执行操作
    light.switch() // The light is off, turn it on.
    light.switch() // The light is on, turn it off.
    light.switch() // The light is off, turn it on.
}
1.2java实现

在java中,实现状态模式的一种方式是使用枚举类,因为枚举类也可以表示一个有限的状态集合,而且可以实现接口或抽象类,从而定义不同的行为。例如,用java实现上面的例子,可以用以下的代码:

// 定义一个接口表示状态
interface State {
    // 定义一个抽象方法表示操作
    void operate();
}

// 定义一个枚举类表示状态,实现State接口
enum LightState implements State {
    // 定义两个枚举常量,分别表示开和关状态
    // 在每个枚举常量的构造器中,传入一个State对象,表示该状态下的行为
    ON(new State() {
        // 重写操作方法,打印信息并切换到关状态
        @Override
        public void operate() {
            System.out.println("The light is on, turn it off.");
            Light.state = OFF;
        }
    }),
    OFF(new State() {
        // 重写操作方法,打印信息并切换到开状态
        @Override
        public void operate() {
            System.out.println("The light is off, turn it on.");
            Light.state = ON;
        }
    });

    // 定义一个私有的State属性,表示该枚举常量对应的状态对象
    private final State state;

    // 定义一个私有的构造器,接收一个State对象作为参数,赋值给state属性
    private LightState(State state) {
        this.state = state;
    }

    // 定义一个公共的方法,调用state属性的operate方法
    public void operate() {
        state.operate();
    }
}

// 定义一个电灯类,它有一个状态属性,初始为关状态
class Light {
    // 定义一个静态的LightState属性,表示电灯的状态,初始为OFF
    public static LightState state = LightState.OFF;

    // 定义一个方法,根据当前状态执行操作
    public void switch() {
        state.operate();
    }
}

// 测试代码
public class Main {
    public static void main(String[] args) {
        // 创建一个电灯对象
        Light light = new Light();
        // 调用switch方法,根据当前状态执行操作
        light.switch(); // The light is off, turn it on.
        light.switch(); // The light is on, turn it off.
        light.switch(); // The light is off, turn it on.
    }
}

可以看出,使用kotlin的密封类实现状态模式的优点是:

  • 代码更简洁,不需要定义接口或抽象类,也不需要使用匿名内部类
  • 代码更安全,不需要担心在其他地方出现未知的状态,也不需要使用else分支处理默认情况
  • 代码更易读,可以清楚地看出状态之间的层次关系和转换逻辑

使用java的枚举类实现状态模式的优点是:

  • 代码更统一,不需要在不同的类中定义状态,也不需要使用对象来表示状态
  • 代码更高效,不需要创建多个状态对象,也不需要使用多态来调用操作方法

2. 访问者模式

访问者模式是一种行为型设计模式,它允许在不修改已有类的结构的情况下,定义作用于这些类的新操作。访问者模式将元素的结构和元素的操作分离,使得操作可以根据不同的元素类型而变化。

2.1kotlin实现

在kotlin中,可以使用密封类来实现访问者模式,因为密封类可以表示一个有限的元素集合,而且可以在when表达式中进行完备的检查,不需要使用else分支。例如,假设有一个表达式类,它有两种子类:数字和加法,每种子类都可以被访问者访问,执行不同的操作。可以用以下的代码来实现:

// 定义一个密封类表示表达式
sealed class Expr {
    // 定义一个抽象方法表示接受访问者的访问
    abstract fun <R> accept(visitor: Visitor<R>): R
}
    // 定义一个数字的子类,继承Expr类,有一个value属性表示数字的值
    data class Num(val value: Int) : Expr() {
        // 重写accept方法,调用访问者的visitNum方法,传入自己作为参数
        override fun <R> accept(visitor: Visitor<R>): R {
            return visitor.visitNum(this)
        }
    }

    // 定义一个加法的子类,继承Expr类,有两个Expr属性表示左右操作数
    data class Sum(val left: Expr, val right: Expr) : Expr() {
        // 重写accept方法,调用访问者的visitSum方法,传入自己作为参数
        override fun <R> accept(visitor: Visitor<R>): R {
            return visitor.visitSum(this)
        }
    }

    // 定义一个访问者接口,泛型参数R表示访问的结果类型
    interface Visitor<R> {
        // 定义一个访问数字的方法,接收一个Num对象作为参数,返回一个R类型的结果
        fun visitNum(num: Num): R
        // 定义一个访问加法的方法,接收一个Sum对象作为参数,返回一个R类型的结果
        fun visitSum(sum: Sum): R
    }

    // 定义一个求值的访问者类,实现Visitor接口,泛型参数为Int
    class EvalVisitor : Visitor<Int> {
        // 重写访问数字的方法,返回数字的值
        override fun visitNum(num: Num): Int {
            return num.value
        }
        // 重写访问加法的方法,返回左右操作数的求值结果的和
        override fun visitSum(sum: Sum): Int {
            return sum.left.accept(this) + sum.right.accept(this)
        }
    }

    // 定义一个打印的访问者类,实现Visitor接口,泛型参数为String
    class PrintVisitor : Visitor<String> {
        // 重写访问数字的方法,返回数字的字符串表示
        override fun visitNum(num: Num): String {
            return num.value.toString()
        }
        // 重写访问加法的方法,返回加法的字符串表示,用括号括起来
        override fun visitSum(sum: Sum): String {
            return "(${sum.left.accept(this)} + ${sum.right.accept(this)})"
        }
    }

    // 测试代码
    fun main() {
        // 创建一个表达式对象,表示1 + (2 + 3)
        val expr = Sum(Num(1), Sum(Num(2), Num(3)))
        // 创建一个求值的访问者对象
        val evalVisitor = EvalVisitor()
        // 创建一个打印的访问者对象
        val printVisitor = PrintVisitor()
        // 调用表达式的accept方法,传入求值的访问者,打印求值的结果
        println(expr.accept(evalVisitor)) // 6
        // 调用表达式的accept方法,传入打印的访问者,打印表达式的字符串表示
        println(expr.accept(printVisitor)) // (1 + (2 + 3))
    }

可以看出,使用kotlin的密封类实现访问者模式的优点是:

  • 代码更简洁,不需要定义抽象方法或接口,也不需要使用类型转换或类型检查
  • 代码更安全,不需要担心在其他地方出现未知的表达式类型,也不需要使用else分支处理默认情况
  • 代码更易读,可以清楚地看出表达式之间的层次关系和访问者的操作逻辑
2.2 java实现
// 抽象元素
interface Animal {
    void accept(Visitor visitor); // 接受一个抽象访问者
}

// 具体元素Lion
class Lion implements Animal {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 调用具体访问者对自己进行操作
    }

    public String roar() {
        return "Roar!";
    }
}

// 具体元素Tiger
class Tiger implements Animal {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 调用具体访问者对自己进行操作
    }

    public String growl() {
        return "Growl!";
    }
}

// 具体元素Elephant
class Elephant implements Animal {
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 调用具体访问者对自己进行操作
    }

    public String trumpet() {
        return "Trumpet!";
    }
}

// 抽象访问者
interface Visitor {
    void visit(Lion lion); // 访问具体元素Lion

    void visit(Tiger tiger); // 访问具体元素Tiger

    void visit(Elephant elephant); // 访问具体元素Elephant
}

// 具体访问者Feed
class Feed implements Visitor {
  @Override 
  public void visit(Lion lion) { 
      System.out.println("Feed the lion with meat.");
  } 

  @Override 
  public void visit(Tiger tiger) { 
      System.out.println("Feed the tiger with chicken.");
  } 

  @Override 
  public void visit(Elephant elephant) { 
      System.out.println("Feed the elephant with banana.");
  } 
}

// 具体访问者Observe
class Observe implements Visitor { 
  @Override 
  public void visit(Lion lion) { 
      System.out.println("Observe the lion: " + lion.roar());
  } 

  @Override 
  public void visit(Tiger tiger) { 
      System.out.println("Observe the tiger: " + tiger.growl());
  } 

  @Override 
  public void visit(Elephant elephant) { 
      System.out.println("Observe the elephant: " + elephant.trumpet());
  }  
}

// 具体访问者Train
class Train implements Visitor {  
   @Override  
   public void visit(Lion lion) {  
       System.out.println("Train the lion to jump through a hoop.");  
   }  

   @Override  
   public void visit(Tiger tiger) {  
       System.out.println("Train the tiger to stand on a ball.");  
   }  

   @Override  
   public void visit(Elephant elephant) {  
       System.out.println("Train the elephant to sit on a stool.");  
   }   
}  

// 对象结构类Zoo

class Zoo {

 private List<Animal> animals = new ArrayList<>();

 // 添加一个新动物   
public void add(Animal animal) {   
     animals.add(animal);   
}   

 // 移除一个已有动物   
public void remove(Animal animal) {   
     animals.remove(animal);   
}   

 // 接受一个抽象访问者,并将所有动物传递给它进行处理    
public void accept(Visitor visitor) {    
     for (Animal animal : animals) {    
         animal.accept(visitor);    
     }    
}   
}

测试代码:

public class Test {

   public static void main(String[] args) {

       Zoo zoo = new Zoo();

       zoo.add(new Lion());
       zoo.add(new Tiger());
       zoo.add(new Elephant());

       Visitor feed = new Feed();
       Visitor observe = new Observe();
       Visitor train = new Train();

       zoo.accept(feed);
       zoo.accept(observe);
       zoo.accept(train);
   }
}

运行测试代码并显示输出结果:

Feed the lion with meat.
Feed the tiger with chicken.
Feed the elephant with banana.
Observe the lion: Roar!
Observe the tiger: Growl!
Observe the elephant: Trumpet!
Train the lion to jump through a hoop.
Train the tiger to stand on a ball.
Train the elephant to sit on a stool.

五、与final类对比

特性密封类final类
可继承性部分可继承,只能被指定的类继承不可继承
受保护成员或虚成员不允许,因为密封类的子类必须是密封类或final类允许,因为final类没有子类
抽象性允许,因为密封类可以是抽象的或具体的不允许,因为抽象类必须被继承
相似之处都是限制类的继承,都不能声明为抽象的,都可以继承别的类或接口都是限制类的继承,都不能声明为抽象的,都可以继承别的类或接口
不同之处可以指定哪些类可以作为其子类,可以实现多态性,可以用于一些特定的设计模式不能有任何子类,不能实现多态性,不能用于一些特定的设计模式
优点可以保证封装性和多态性,可以提高代码的可读性和可维护性,可以避免不必要的继承或实现可以保证封装性和不变性,可以提高代码的执行效率,可以避免类的滥用
缺点可能增加代码的复杂度和冗余,可能限制类的扩展性和灵活性,可能与一些框架或库不兼容可能增加代码的耦合度和僵化度,可能限制类的扩展性和灵活性,可能与一些框架或库不兼容
应用场景可以用于实现一些特定的设计模式,例如状态模式、策略模式、访问者模式等,这些模式需要明确地定义一组有限的子类或实现类可以用于实现一些不需要继承的类,例如工具类、常量类、单例类等,这些类需要保证其不变性和唯一性


六、应用

如果说,我们一个需求,控制档位,有两种模式,一种是inch 一种是mm。怎么表达?

我们想到是两个数组一一对应,如果java写就是枚举。

public class Test {
    public static void main(String[] args) {
        System.out.println("根据英文描述获取中文描述:" + ColorEnum.getDescriptionByCode(ColorEnum.YELLOW.getCode()));
        System.out.println("根据输入字符获取中文描述(有):" + ColorEnum.getDescriptionByCode("RED"));
        System.out.println("根据输入字符获取中文描述(无):" + ColorEnum.getDescriptionByCode("PURPLE"));
    }
}
 
enum ColorEnum {
    YELLOW("YELLOW", "黄色"),
    WHITE("WHITE", "白色"),
    GREEN("GREEN", "绿色"),
    BLUE("BLUE", "蓝色"),
    RED("RED", "红色");
 
    //枚举标识码(中文描述)
    private final String description;
 
    //这个必须定义,且成员变量的类型及个数必须对应于上边枚举的定义
    //枚举标识码(英文描述)
    private final String code;
 
    ColorEnum(String code, String description) {
        this.code = code;
        this.description = description;
    }
 
    public String getCode() {
        return code;
    }
 
    public String getDescription() {
        return description;
    }
 
    public static String getDescriptionByCode(String code) {
        for (ColorEnum value : ColorEnum.values()) {
            if (value.getCode().equals(code)) {
                return value.getDescription();
            }
        }
        return null;
    }
}
 
执行结果:
根据英文描述获取中文描述:黄色
根据输入字符获取中文描述(有):红色
根据输入字符获取中文描述(无):null

那么kotlin怎么写:

用data数据类+密封类

sealed class OrderStatus {
    abstract val orderId: String

    data class Pending(override val orderId: String) : OrderStatus()
    data class Shipped(override val orderId: String, val trackingNumber: String) : OrderStatus()
    data class Delivered(override val orderId: String, val deliveryDate: String) : OrderStatus()
    object Cancelled : OrderStatus()

    fun getDescription(): String {
        return when (this) {
            is Pending -> "Order $orderId is pending"
            is Shipped -> "Order $orderId has been shipped with tracking number $trackingNumber"
            is Delivered -> "Order $orderId has been delivered on $deliveryDate"
            Cancelled -> "Order $orderId has been cancelled"
        }
    }
}

fun main() {
    val pendingOrder = OrderStatus.Pending("12345")
    val shippedOrder = OrderStatus.Shipped("67890", "XYZ123")
    val deliveredOrder = OrderStatus.Delivered("23456", "2023-09-25")
    val cancelledOrder = OrderStatus.Cancelled

    println(pendingOrder.getDescription())
    println(shippedOrder.getDescription())
    println(deliveredOrder.getDescription())
    println(cancelledOrder.getDescription())
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【软件基础知识】什么是 API,详细解读

想象一下,你正在使用智能手机上的天气应用。你打开应用,瞬间就能看到实时天气、未来预报,甚至是空气质量指数。但你有没有想过,这些数据是如何神奇地出现在你的屏幕上的?答案就在三个字母中:API。 API,全称Application Programming Interface(应用程序编程接口),是现代软件世…

MYSQL面试知识点手册

第一部分&#xff1a;MySQL 基础知识 1.1 MySQL 简介 MySQL 是世界上最流行的开源关系型数据库管理系统之一&#xff0c;它以性能卓越、稳定可靠和易用性而闻名。MySQL 主要应用在 Web 开发、大型互联网公司、企业级应用等场景&#xff0c;且广泛用于构建高并发、高可用的数据…

工程师 - PFM介绍

在电子电路设计中&#xff0c;PFM&#xff08;Pulse Frequency Modulation&#xff0c;脉冲频率调制&#xff09;是一种调制技术&#xff0c;其主要特点是在负载变化时调整脉冲的频率&#xff0c;而保持脉冲的宽度&#xff08;时间长度&#xff09;相对恒定。与PWM&#xff08;…

记忆化搜索专题——算法简介力扣实战应用

目录 1、记忆化搜索算法简介 1.1 什么是记忆化搜索 1.2 如何实现记忆化搜索 1.3 记忆化搜索与动态规划的区别 2、算法应用【leetcode】 2.1 题一&#xff1a;斐波那契数 2.1.1 递归暴搜解法代码 2.1.2 记忆化搜索解法代码 2.1.3 动态规划解法代码 2.2 题二&#xff1…

Transformer预测 | 基于Transformer心率时间序列预测(tensorflow)

效果一览 基本介绍 Transformer预测 | 基于Transformer心率时间序列预测(tensorflow) 程序设计 import pandas as pd from pandas.plotting import lag_plot from statsmodels.graphics

加密与安全_优雅存储二要素(AES-256-GCM )

文章目录 什么是二要素如何保护二要素&#xff08;姓名和身份证&#xff09;加密算法分类场景选择算法选择AES - ECB 模式 (不推荐)AES - CBC 模式GCM&#xff08;Galois/Counter Mode&#xff09;AES-256-GCM简介AES-256-GCM工作原理安全优势 应用场景其他模式 和 敏感数据加密…

AIoT智能工控板

在当今竞争激烈的商业环境中&#xff0c;企业需要强大的科技力量来助力腾飞&#xff0c;AIoT智能工控板就是这样的力量源泉。 其领先的芯片架构设计&#xff0c;使得主板的性能得到了极大的提升。无论是数据的处理速度、图形的渲染能力&#xff0c;还是多任务的并行处理能力&a…

Ceph官方文档_01_Ceph简介

目录 Ceph介绍Ceph介绍 Ceph可用于向云平台提供Ceph对象存储,Ceph可用于向云平台提供Ceph块设备服务。Ceph可用于部署Ceph文件系统。所有Ceph存储群集部署开始都是先设置每个Ceph节点,然后再设置网络。 Ceph存储集群需要以下内容:至少一个Ceph监视器和至少一个Ceph管理器,…

毕业设计选题:基于ssm+vue+uniapp的捷邻小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

Linux top命令详解与重点内容说明

文章目录 重点说明基本信息进程(任务)信息cpu占用信息%Cpu(s)内存信息交换内存信息每列含义说明交互命令多窗口模式颜色配置命令参数 重点说明 top命令非常强大&#xff0c;也非常复杂&#xff0c;很难面面俱到&#xff0c;也没有必要&#xff0c;这篇文章的目的是介绍重点&am…

en造数据结构与算法C# 群组行为优化 和 头鸟控制

实现&#xff1a; 1.给鸟类随机播放随机动画使得每一只鸟扇翅膀的频率都不尽相同 2.可以自行添加权重&#xff0c;并在最后 sumForce separationForce cohesionForce alignmentForce;分别乘上相应权重&#xff0c;这样鸟就能快速飞行和转向辣 using System.Collections.Ge…

Linux系统编程(基础指令)上

1.Linux常见目录介绍 Linux目录为树形结构 /&#xff1a;根目录&#xff0c;一般根目录下只存放目录&#xff0c;在Linux下有且只有一个根目录。所有的东西都是从这里开始。当你在终端里输入“/home”&#xff0c;你其实是在告诉电脑&#xff0c;先从/&#xff08;根目录&…

Unity3D入门(二) :Unity3D实现视角的丝滑过渡切换

1. 前言 上篇文章&#xff0c;我们已经初步了解了Unity3D&#xff0c;并新建并运行起来了一个项目&#xff0c;使相机视角自动围绕着立方体旋转。 这篇文章&#xff0c;我们来讲一下Unity3D怎么过渡地切换视角。 我们继续是我上篇文章中的项目&#xff0c;但是需要向把Camera…

​OpenAI最强模型o1系列:开启人工智能推理新时代

前不久OpenAI发布全新模型——o1模型&#xff0c;也就是业界说的“草莓模型”&#xff0c;包含三款型号&#xff1a;OpenAI o1、OpenAI o1-preview和OpenAI o1-mini。 其中&#xff0c;OpenAI o1-mini和 o1-preview已经对用户开放使用&#xff1a; OpenAI o1&#xff1a;高级推…

企业急于采用人工智能,忽视了安全强化

对主要云提供商基础设施上托管的资产的安全分析显示&#xff0c;许多公司为了急于构建和部署 AI 应用程序而打开安全漏洞。常见的发现包括对 AI 相关服务使用默认且可能不安全的设置、部署易受攻击的 AI 软件包以及不遵循安全强化指南。 这项分析由 Orca Security 的研究人员进…

Redis学习以及SpringBoot集成使用Redis

目录 一、Redis概述 二、Linux下使用Docker安装Redis 三、SpringBoot集成使用Redis 3.1 添加redis依赖 3.2 配置连接redis 3.3 实现序列化 3.4 注入RedisTemplate 3.5 测试 四、Redis数据结构 一、Redis概述 什么是redis&#xff1f; redis 是一个高性能的&#xf…

vue项目加载cdn失败解决方法

注释index.html文件中 找到vue.config.js文件注释、

【Python语言初识(二)】

一、分支结构 1.1、if语句 在Python中&#xff0c;要构造分支结构可以使用if、elif和else关键字。所谓关键字就是有特殊含义的单词&#xff0c;像if和else就是专门用于构造分支结构的关键字&#xff0c;很显然你不能够使用它作为变量名&#xff08;事实上&#xff0c;用作其他…

0基础带你入门Linux之使用

1.Ubuntu软件管理 回顾一下&#xff0c;我们之前使用su root切换到root模式&#xff0c;使用who 发现为什么显示的还是bd用户呢&#xff1f;为什么呢&#xff1f; 这个who是主要来查看的是我们登录的时候是以什么用户登录的 所以即使我们使用who进行查看的时候显示的还是bd用…

【JavaWeb】利用IDEA2024+tomcat10配置web6.0版本搭建JavaWeb开发项目

之前写过一篇文章&#xff1a;《【JavaWeb】利用IntelliJ IDEA 2024.1.4 Tomcat10 搭建Java Web项目开发环境&#xff08;图文超详细&#xff09;》详细讲解了如何搭建JavaWeb项目的开发环境&#xff0c;里面默认使用的Web版本是4.0版本的。但在某些时候tomcat10可能无法运行we…