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

深入解析Kotlin类与对象:构造、伴生、单例全面剖析

前言

本篇文章将带您了解Kotlin编程中的重要概念:类及构造函数、访问修饰符、伴生对象和单例模式。就像搭积木一样,我们会逐步揭开这些概念的面纱,让您轻松理解它们的作用和用法。无论您是编程新手还是有经验的开发者,本文都将为您提供有趣而易懂的内容,帮助您更好地掌握Kotlin中类与对象的重要知识点。让我们一起开始这段有趣的学习之旅吧!

一、Kotlin 的类以及构造函数

1、声明一个类

当你使用 class 关键字在 Kotlin 中声明一个类时,其基本的语法格式如下所示:

class ClassName {// 类的成员变量和方法在这里定义
}

2、关于Kotlin类的继承和接口实现的规则

(1)继承父类

如果一个类有父类,你可以在类的声明中使用冒号 : 后面跟着父类的名称。这称为类的继承。例如:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 在这里可以进行一些初始化操作}
}
  • 继承父类无参构造函数:如果父类有一个无参构造函数,子类可以省略括号,并且不需要在子类中声明构造函数。这适用于父类的构造函数没有参数的情况,或者所有参数都有默认值。

  • 继承父类有参构造函数:如果父类的构造函数有参数,或者你想在子类中添加自己的构造函数,就需要根据具体情况使用括号并传递必要的参数。

(2)默认父类

如果一个类没有显式声明父类,它的默认父类是 Any 类,而不是 Object 类。Any 是 Kotlin 根类层次结构的顶层类型。所有的 Kotlin 类都直接或间接地继承自 Any 类。

Any 类的声明如下:

public open class Any

在 Kotlin 中,默认情况下,所有类都隐式地继承自 Any 类,即使你没有明确指定。因此,以下两个类声明是等价的:

class MyClass
class MyClass : Any()

这就是为什么你在 Kotlin 中无需显式指定父类,而默认情况下所有类都已经继承自 Any

需要注意的是,Any 类定义了一些通用方法,如 equalshashCodetoString,因此所有的 Kotlin 类都会具备这些方法。

(3)接口实现

在 Kotlin 中,可以在类的声明后面使用冒号 : 来实现一个或多个接口。你不需要显式使用 implements 关键字。例如:

import android.os.Bundle
import android.view.View
import android.widget.Button
import androidx.appcompat.app.AppCompatActivityclass MainActivity : AppCompatActivity(), View.OnClickListener {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val button = findViewById<Button>(R.id.button)button.setOnClickListener(this)}override fun onClick(v: View?) {when (v?.id) {R.id.button -> {// 在这里定义按钮点击事件的逻辑}}}
}

在上面的示例中,我们首先让 MainActivity 类实现了 View.OnClickListener 接口,并重写了其中的 onClick 方法。然后,我们在 onCreate 方法中使用 setOnClickListener(this) 将当前 MainActivity 对象作为按钮的点击监听器。

在 Kotlin 中,你是可以先写接口后写父类,或者先写父类后写接口,都是完全合法的。在类的声明中,继承父类和实现接口的顺序可以根据你的需求进行灵活安排。

3、open 关键字的作用

在 Kotlin 中,默认情况下,类是 publicfinal 的,这意味着它们对外部可见,并且不能被继承。如果你希望其他类能够继承这个类,你需要使用 open 关键字来声明这个类,使它变成可继承的。

在 Kotlin 中,修饰符的含义如下:

  • public:表示该成员(类、函数、属性等)在任何地方都可见。
  • final:表示类、函数或属性不能被继承或覆盖(重写),在类级别指的是类不能被继承。
  • open:用于修饰类、函数或属性,表示它们可以被继承或覆盖。

如果你想要创建一个可被继承的类,你需要使用 open 修饰符。

例如,当你想在 Android 应用中创建一个可被继承的 MainActivity 类时,你需要在类的声明前面加上 open 修饰符,以允许其他类继承它。这样,其他类就可以继承 MainActivity 并在子类中进行扩展。

以下是一个示例,展示如何在 Android 应用中创建一个可被继承的 MainActivity 类:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivityopen class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)// 在这里可以进行一些初始化操作}
}

在这个示例中,我们创建了一个名为 MainActivity 的类,继承自 AppCompatActivity,这是 Android 中用于创建活动(Activity)的基类。注意,在类的声明中,我们使用了 open 修饰符,允许其他类继承这个 MainActivity

其他类可以继承这个 MainActivity 并在子类中进行扩展,例如:

class CustomActivity : MainActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 在这里可以进行自定义的初始化操作}
}

在上面的示例中,CustomActivity 类继承自 MainActivity,并在子类中重写了 onCreate 方法,实现了自定义的初始化操作。

总结,通过使用 open 修饰符,你可以在 Android 应用中创建一个可被继承的基类,让其他类能够继承它并在子类中添加自己的功能。

4、主构造函数和次构造函数

构造函数是用于创建对象的特殊方法,它在对象创建时被调用,通常用于执行初始化操作。在 Kotlin 中,类可以有一个主构造函数和多个次构造函数。

(1)主构造函数

当涉及到在 Kotlin 类中创建实例时,主构造函数扮演着重要的角色。主构造函数允许在对象被实例化时接收参数,并且对对象的属性进行初始化。以下是关于主构造函数的概要:

  • 声明方式:主构造函数是类定义的一部分,紧随类名后面的括号中可以包含参数列表。如果主构造函数没有其他修饰符,那么括号可以省略。
  • 参数传递:主构造函数的参数可以在整个类范围内使用,不仅限于初始化代码块。你可以将这些参数直接用于属性的初始化。
  • 初始化代码块:主构造函数也可以包含初始化代码块,使用 init 关键字定义。在这个代码块中,你可以编写在对象初始化时执行的代码。

以下是一个示例,展示了如何声明主构造函数、使用参数初始化属性,并在初始化代码块中执行逻辑,其中使用了自定义视图类 CustomView

class CustomView(context: Context, attrs: AttributeSet): View(context, attrs) {private val paint: Paint = Paint()init {paint.color = Color.BLACK}
}

在上述示例中,CustomView 类继承自 View,并在主构造函数中接收了 contextattributeSet 参数。

在类的主体中,声明了一个名为 paint 的私有属性,并在初始化时进行了属性初始化。使用了 Paint 类,这是 Android 中用于绘制图形和文本的工具类。

在类的 init 块中,设置了 paint 的颜色为黑色(Color.BLACK)。这将确保 paint 对象在视图实例化时就被配置为黑色,以便在后续的绘制操作中使用。

当创建 CustomView 的实例时,会触发 init 块中的代码执行,从而完成属性的初始化设置。init 块是一个在对象实例化时执行初始化代码的地方,它允许你在构造函数中接收参数,并在 init 块中执行必要的初始化逻辑。在自定义视图类中,你可以使用 init 块来确保对象在使用之前处于正确的状态。

(2)次构造函数

次构造函数是在 Kotlin 中用于提供额外的构造函数选项的一种方式。它允许你在同一个类中定义多个不同参数集的构造函数,以满足不同的初始化需求。次构造函数通常调用主构造函数或者其他次构造函数,确保共享的初始化逻辑被重复使用。

以下是关于次构造函数的一些重要信息:

  • 声明方式:次构造函数通过 constructor 关键字声明,紧随其后的括号内包含参数列表。次构造函数可以有不同的参数集,但不能直接初始化属性。
  • 调用主构造函数:在次构造函数内部,你可以使用 this() 调用主构造函数,确保共享的初始化逻辑被执行。调用主构造函数时,可以传递相应的参数。
  • 调用其他次构造函数:在次构造函数内部,你也可以使用 this() 调用同一个类中的其他次构造函数。这样可以避免重复编写初始化逻辑。

以下是一个示例,展示了如何在 CustomView 类中使用次构造函数:

class CustomView : View {constructor(context: Context) : this(context, null, 0)constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {initialize(context, attrs, defStyleAttr)}private fun initialize(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {// 在这里执行初始化操作}}

在上面的示例中,CustomView 类继承自 Android 中的 View 类,并且有三个构造函数:

  • 第一个构造函数接收一个 context 参数,这是主构造函数。它通过调用次构造函数,为 attrsdefStyleAttr 提供默认值。
  • 第二个构造函数接收 contextattrs 参数,调用了具有更多参数的次构造函数。
  • 第三个构造函数接收 contextattrsdefStyleAttr 参数,它是主要的构造函数。它通过调用父类 View 的构造函数来实现,并在构造函数内部调用了 initialize 函数来执行额外的初始化操作。

(3)大家来找茬

可以尝试将下面示例代码放到编译器中,会发现编译不通过, super 处会提示 “Primary constructor call expected”。问题出在了哪里?

class CustomView(context: Context) : View(context) {constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) {initialize(context, attrs, 0)}constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {initialize(context, attrs, defStyleAttr)}private fun initialize(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {// 在这里执行初始化操作}}

错误消息 “Primary constructor call expected” 意味着在构造函数的调用位置需要调用主构造函数,但实际上没有调用。

在 Kotlin 中,如果一个类有一个主构造函数,那么所有的次构造函数必须委托给主构造函数。这是语言的规定,确保类的初始化能够始终通过主构造函数完成。

在我们的代码中,主构造函数是 class CustomView(context: Context) : View(context) 这一行。由于它是一个主构造函数,所有的次构造函数必须通过 this() 来调用主构造函数。因此,不能在次构造函数中使用 super 关键字来调用父类的构造函数。

以下是修正后的代码示例,满足了 Kotlin 的构造函数规定:

class CustomView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : View(context, attrs, defStyleAttr) {constructor(context: Context) : this(context, null, 0) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)init {initialize(context, attrs, defStyleAttr)}private fun initialize(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {// 在这里执行初始化操作}
}

在这个修正后的代码中,主构造函数是 class CustomView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : View(context, attrs, defStyleAttr) ,并且所有的次构造函数都通过 this() 来委托主构造函数。统一在 init 添加初始化操作,以满足我们的需求。

(4)@JvmOverloads 注解

使用了 @JvmOverloads 注解来为 CustomView 类的构造函数生成所有可能的参数组合,以简化构造函数的使用。这样,你可以使用主构造函数,也可以选择性地使用次构造函数。

我们将上述代码再次改造一下:

class CustomView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {init {initialize(context, attrs, defStyleAttr)}private fun initialize(context: Context, attrs: AttributeSet?, defStyleAttr: Int) {// 在这里执行初始化操作}
}

使用这个示例,你可以这样创建一个 CustomView 实例:

val customView1 = CustomView(context)  
val customView2 = CustomView(context, attrs)  
val customView3 = CustomView(context, attrs, defStyleAttr)  

@JvmOverloads 是 Kotlin 中的一个注解,用于在编译器级别生成多个重载版本的函数或构造函数,以便在 Java 代码中更方便地使用。这个注解通常用于改善 Kotlin 类在 Java 代码中的互操作性。

在特定情况下,Kotlin 的函数或构造函数可能具有默认参数,这使得在 Kotlin 中调用它们非常方便,因为可以省略部分参数。但在 Java 中,调用具有默认参数的 Kotlin 函数会变得不那么直观,因为 Java 不直接支持 Kotlin 的默认参数语法。

这时,@JvmOverloads 就派上用场了。当你在 Kotlin 函数或构造函数上使用 @JvmOverloads 注解时,Kotlin 编译器会自动为每个省略参数的版本生成一个重载版本,以便在 Java 代码中使用。这样,Java 开发者就可以根据需要传递不同数量的参数,而不必理解或设置 Kotlin 的默认参数。

具体来说,对于构造函数来说,@JvmOverloads 会在编译时为每个可能的参数组合生成一个单独的构造函数,以确保 Java 开发者能够使用所有参数组合。

总结:@JvmOverloads 是一个用于改善 Kotlin 代码在 Java 中互操作性的注解,它为具有默认参数的函数或构造函数生成重载版本,使得 Java 开发者能够更方便地使用这些函数或构造函数。

(5)init 函数,父类的构造函数与次构造函数之间调用顺序

  • 首先,会执父类的 init 块(如果有的话)
  • 其次,会执行父类的构造函数(主构造函数或者被次构造函数调用的构造函数)。
  • 然后,会执行当前类的 init 块(如果有的话)。
  • 最后,会执行当前类的次构造函数(如果有的话)。

以下是一个示例来说明这个调用顺序:

open class Parent {init {println("Parent's init block")}constructor() {println("Parent's constructor")}
}class Child : Parent {constructor() : super() {println("Child's constructor")}init {println("Child's init block")}
}fun main() {val obj = Child()
}

在这个示例中,当创建 Child 类的实例时,首先会调用 Parent 类的 init 块,其次是 Parent 类的构造函数,然后执行 Child 类的 init 块,最后执行 Child 类的次构造函数。因此,输出将是:

Parent's init block
Parent's constructor
Child's init block
Child's constructor

二、访问修饰符

在 Kotlin 中,访问修饰符用于控制类、接口、函数、属性等成员的可见性。Kotlin 提供了一些访问修饰符,用于指定成员在哪些范围内可见。以下是常见的访问修饰符:

  1. public(默认):没有显式指定访问修饰符时,默认为 public。在这种情况下,成员对所有其他代码都可见。
  2. private:成员只在声明它的文件中可见。私有成员对同一文件中的其他类都不可见。
  3. protected:成员在声明它的类及其子类中可见。但在同一包内的其他类中不可见。
  4. internal:成员对于同一模块内的所有代码都可见。模块是一组一起编译的 Kotlin 文件。它更多的去用于我们现在做一些项目的结构化的扩展的时候去使用这个修饰符。

示例:

class MyClass {private val privateVar = 1protected val protectedVar = 2internal val internalVar = 3val publicVar = 4 // 默认为 public
}fun main() {val obj = MyClass()println(obj.internalVar) // 可以访问,因为处于同一模块内println(obj.publicVar)   // 可以访问,因为是 public// 下面的代码不能编译通过,因为 private 和 protected 变量不在可见范围内// println(obj.privateVar)// println(obj.protectedVar)
}

注意:

  • 对于顶层声明(不在类内部的声明),只有 publicinternal 修饰符有效。
  • internal 修饰符在 Kotlin 中非常有用,它允许模块内的代码访问成员,同时限制了模块之间的访问。
  • privateprotected 对于顶层声明(不在类内部的声明)是无效的,因为它们只对类内部的成员可见性起作用。

综上所述,访问修饰符用于控制代码中成员的可见性范围,确保代码的封装和安全性。

补充一下,什么是模块?

每当创建一个 module,这就是一个模块。如果你的一个变量名通过internal修饰的话,在同一个模块内的时候,是可以互相调用的,但是跨模块的话,你是无法访问到这个变量的。这就是 kotlin 的这个访问修饰符,它更多的去用于我们现在做一些项目的结构化的扩展的时候去使用这个修饰符。

在这里插入图片描述

三、伴生对象

在 Kotlin 中,每个类都可以有一个伴生对象(Companion Object),它是该类的一个特殊对象实例。伴生对象的成员可以像 Java 静态成员一样在类级别上访问,不需要通过类的实例来调用。伴生对象通常用于创建类级别的静态成员、工厂方法、单例模式等。

在 JAVA 中,我们经常看到这样的一段代码,就是工具类,里面定义了一些的静态方法,可以直接用工具类的类名 . 方法名,去调用它。如下所示:

public class StringUtils {public static final String EMPTY = "";public static boolean isEmpty(CharSequence cs) {return cs == null || cs.length() == 0;}public static boolean isNotEmpty(CharSequence cs) {return !StringUtils.isEmpty(cs);}
}

但是在 kotlin 中是没有静态方法的,Kotlin 要怎么改写呢?

方法有两种,第一种办法是我们在《Kotlin 代码与 Java 代码集成》中介绍过,使用 @JvmStatic 注释暴露 Kotlin 类的静态方法。

那么第二种方法就是现在要介绍的伴生对象 Companion Object ,它必须被写在一个类的内部,作为这个类的伴生对象。伴生对象可以包含成员函数、属性和初始化代码块,类似于 Java 中的静态成员。它的一个主要作用是允许在不创建类实例的情况下访问这些成员,就像访问静态成员一样。

那么我们来改写一下:

class StringUtils {companion object {const val EMPTY = ""fun isEmpty(cs: CharSequence?): Boolean {return cs.isNullOrEmpty()}fun isNotEmpty(cs: CharSequence?): Boolean {return !isEmpty(cs)}}
}

在上面的示例中,StringUtils 类中定义了一个伴生对象,其中包含一个常量 EMPTY 和 两个方法isEmptyisNotEmpty。那么就可以在类级别上直接访问伴生对象的成员和方法,就像访问类的静态成员和静态方法一样。

在 Java 代码中调用,如下所示:

 public class JavaExample {public static void main(String[] args) {String str = "";boolean isEmpty = StringUtils.Companion.isEmpty(str);boolean isNotEmpty = StringUtils.Companion.isNotEmpty(str);System.out.println("isEmpty: " + isEmpty);System.out.println("isNotEmpty: " + isNotEmpty);}
}

注意,StringUtils.Companion 中的 Companion 是伴生对象的默认名称,因为我们并未显式地为我们的伴生对象命名,伴生对象的名称可以省略,那么此时使用默认的名称 Companion

实际上伴生对象在编译好以后会在这个类的内部生成一个静态对象。叫companion的对象,那么我们Java在调用的时候,实际上是通过这个类的companion对象去调用companion内部的一些变量。

如果你为伴生对象显式命名,例如 MyCompanion,那么需要使用该名称来访问伴生对象的成员。以下是一个使用了命名伴生对象的示例:

class StringUtils {companion object MyCompanion {const val EMPTY = ""fun isEmpty(cs: CharSequence?): Boolean {return cs.isNullOrEmpty()}fun isNotEmpty(cs: CharSequence?): Boolean {return !isEmpty(cs)}}
}

在 Java 代码中调用,如下所示:

 public class JavaExample {public static void main(String[] args) {String str = "";boolean isEmpty = StringUtils.MyCompanion.isEmpty(str);boolean isNotEmpty = StringUtils.MyCompanion.isNotEmpty(str);System.out.println("isEmpty: " + isEmpty);System.out.println("isNotEmpty: " + isNotEmpty);}
}

四、单例

半生对象在 Kotlin 中还有一个非常有用的特性,就是可以用于声明单例。在前面的文章中,我们已经介绍了通过 object 关键字来创建匿名的内部类,这种方式其实也可以用来实现单例。然而,更加推荐的写法是利用伴生对象来创建单例。

使用伴生对象来实现单例具有许多优点:

  1. 线程安全: 伴生对象的属性和方法在类加载时进行初始化,确保了线程安全。这样即使在多线程环境下也能保证只有一个实例被创建。
  2. 延迟初始化: 伴生对象的属性和方法是在首次访问时才会被初始化,这也被称为"惰性初始化"。这种方式能够节省资源,只有在实际需要时才会创建实例。
  3. 清晰可见: 伴生对象使得单例模式的实现更加清晰和易于理解。它将单例的代码组织在一起,使得代码结构更加整洁。

总的来说,虽然在 Kotlin 中可以使用 object 关键字来创建单例,但更加推荐使用伴生对象来实现。这种方式不仅更加优雅,还能够带来诸多优势,如线程安全和延迟初始化等。如果你正在考虑实现单例模式,不妨考虑使用伴生对象来达到更好的效果。

以下是如何使用伴生对象来实现单例模式的示例:

class Single private constructor() {companion object {fun get(): Single {return Holder.instance}}private object Holder {val instance = Single()}
}
  • Single 类的主构造函数被声明为私有,这意味着外部无法直接通过构造函数来实例化该类。
  • Single 类的伴生对象中,我们定义了一个名为 get 的方法,用于获取 Single 类的单例实例。该方法返回了一个 Holder 内部对象的实例,这是通过 Holder.instance 访问的。
  • 内部的 Holder 对象的实例化是通过 Kotlin 中的对象声明(object)实现的。由于 Kotlin 的对象声明在首次访问时就会被初始化,且只会被初始化一次,这确保了线程安全的单例创建。

上述代码展示了一种在 Kotlin 中使用伴生对象来创建单例的方式,这是一种非常常见的做法。这种方式结合了私有的主构造函数和内部对象,确保了单例的线程安全性和延迟初始化。

相关文章:

深入解析Kotlin类与对象:构造、伴生、单例全面剖析

前言 本篇文章将带您了解Kotlin编程中的重要概念&#xff1a;类及构造函数、访问修饰符、伴生对象和单例模式。就像搭积木一样&#xff0c;我们会逐步揭开这些概念的面纱&#xff0c;让您轻松理解它们的作用和用法。无论您是编程新手还是有经验的开发者&#xff0c;本文都将为…...

JavaScript构造函数

1、构造函数&#xff1a; 是一个函数&#xff0c;是通过new运算符进行调用&#xff0c;生成一个特殊的对象并返回。 function 函数名([参数]){ this.属性名 ‘属性值’ ... this.属性名 function([参数]){ 函数体语句 } } 通常情况下&#xff0c;建议构造函数的首字母大写 …...

手写嵌入式操作系统(基于stm8单片机)

#include <stc8h.h> #include <intrins.h> #define MAX_TASKS 2 //简化方面,我们当前操作系统只有2个task #define MAX_TASK_DEP 32unsigned char idata task_sp[MAX_TASKS]; // 任务的堆栈指针 unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];// 每个…...

vue3.3 ~

defineModel 原本&#xff1a; // 1 defineProps({modelValue: {type: Number,required: true,default: 0} })defineProps([modelValue]) // 2 const emit defineEmits([update:modelValue])现在&#xff1a; const value defineModel<number>({ default: 0 })defin…...

滑动窗口实例4(将x减到0的最小操作数)

题目&#xff1a; 给你一个整数数组 nums 和一个整数 x 。每一次操作时&#xff0c;你应当移除数组 nums 最左边或最右边的元素&#xff0c;然后从 x 中减去该元素的值。请注意&#xff0c;需要 修改 数组以供接下来的操作使用。 如果可以将 x 恰好 减到 0 &#xff0c;返回 …...

数据库原理及应用(MySQL)

建议大屏观看&#xff0c;避免格式错误&#xff0c;影响观感 目录 第一章 数据库系统概述 1.数据库系统概述 1.1.信息 1.2.数据 1.3.信息和数据之间的联系 1.4.数据库&#xff08;DB&#xff09; 1.5.数据库管理系统&#xff08;DBMS&#xff09; 1.6.数据库管理系统的…...

初识Maven(一)命令行操作和idea创建maven工程

Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供**构建**和**依赖**管理支持的工具。 构建过程包含的主要的环节&#xff1a;- 清理&#xff1a;删除上一次构建的结果&#xff0c;为下一次构建做好准备 - 编译&#xff1a;Java 源程序编译成 *.class 字节码文件…...

MHA高可用配置及故障切换

1&#xff0e;什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过…...

FPGA/IC秋招面试题 1(解析版)

分享个人觉得遇到还不错的题&#xff0c;后续有会继续补充。。。 以下题目均来自网络平台&#xff0c;用于学习交流如有侵权立马删除!!! 1. Verilog语言中&#xff0c;下面哪些语句不可被综合() A. #delay语句 B. initial语句 C. always语句 D. 用gen…...

华为云 异构数据迁移

数据库和应用迁移 UGO&#xff08;Database and Application Migration UGO&#xff0c;以下简称为UGO&#xff09;是专注于异构数据库结构迁移的专业服务。可将源数据库中的DDL、DML和DCL一键自动转换为华为云GaussDB/RDS的SQL语法&#xff0c;通过数据库评估、对象迁移两大核…...

wininet,winhttp,xmlhttprequest,各版本区别 《转》

一、标准API接口WinINet(Microsoft Windows Internet)和WinHTTP(Microsoft Windows HTTP) 实现Http访问&#xff0c;微软提供了二套API&#xff1a;WinINet, WinHTTP&#xff08;分别封装于system32目录下的wininet.dll和winhttp.dll内&#xff09; 二者主要区别在于后者更为安…...

朴素,word,任何参考文献导入endnote

朴素&#xff0c;word&#xff0c;任何参考文献导入endnote 注意&#xff1a;对于以下这几种不做阐述&#xff0c;看其他帖子都有讲述&#xff1a; 这里的参考文献指的是类似于&#xff1a; [1]. Li Y, Lu Y, Huo X, et al. Bandgap tuning strategy by cations and halide io…...

数学建模--三维图像绘制的Python实现

目录 1.绘制三维坐标轴的方法 2.绘制三维函数的样例1 3.绘制三维函数的样例2 4.绘制三维函数的样例3 5.绘制三维函数的样例4 6.绘制三维函数的样例5 1.绘制三维坐标轴的方法 #%% #1.绘制三维坐标轴的方法 from matplotlib import pyplot as plt from mpl_toolkits.mplot3…...

Spring Cloud Alibaba-Feign整合Sentinel

第1步: 引入sentinel的依赖 <!--sentinel客户端--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> 第2步: 在配置文件中开启Feign对Sentinel的…...

zabbix配置钉钉告警、和故障自愈

钉钉告警python脚本 cat python20 #!/usr/bin/python3 #coding:utf-8 import requests,json,sys,os,datetime # 机器人的Webhook地址 webhook"钉钉" usersys.argv[1] textsys.argv[3] data{"msgtype": "text","text": {"conten…...

Web安全测试(五):XSS攻击—存储式XSS漏洞

一、前言 结合内部资料,与安全渗透部门同事合力整理的安全测试相关资料教程,全方位涵盖电商、支付、金融、网络、数据库等领域的安全测试,覆盖Web、APP、中间件、内外网、Linux、Windows多个平台。学完后一定能成为安全大佬! 全部文章请访问专栏:《全栈安全测试教程(0基…...

本地PC机通过SSH方式远程Jetson

1. 检测电脑是否安装openSSH 以管理员身份运行powershell终端输入以下命令&#xff1a; Get-WindowsCapability -Online | ? Name -like OpenSSH*若没有安装OpenSSH&#xff0c;会出现如下图提示&#xff1a; 输入Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.…...

面向对象 学习黑马视频(03)

1.内存分区模型 /* 面向对象编程** 内存分区模型* 1.代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的* 2.全局区&#xff1a;存放全局变量和静态变量以及常量* 3.栈区&#xff1a;由编译器自动分配释放&#xff0c;存放函数的参数值…...

FinClip 支持创建 H5应用类小程序;PC 终端 优化升级

FinClip 的使命是使您能够通过小程序解决关键业务流程挑战&#xff0c;并完成数字化转型。不妨让我们看看本月产品与市场发布亮点&#xff0c;是否有助于您实现目标。 产品方面的相关动向&#x1f447;&#x1f447;&#x1f447; FinClip 支持创建 H5应用类小程序 近期我们…...

YOLOV8实例分割——详细记录环境配置、自定义数据处理到模型训练与部署

前言 Ultralytics YOLOv8是一种前沿的、最先进的&#xff08;SOTA&#xff09;模型&#xff0c;它在前代YOLO版本的成功基础上进行了进一步的创新&#xff0c;引入了全新的特性和改进&#xff0c;以进一步提升性能和灵活性。作为一个高速、精准且易于操作的设计&#xff0c;YO…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...