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

news2024/11/15 17:43:18

前言

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

一、Kotlin 的类以及构造函数

1、声明一个类

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

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

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

(1)继承父类

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

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class 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.AppCompatActivity

class 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.AppCompatActivity

open 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 = 1
    protected val protectedVar = 2
    internal val internalVar = 3
    val 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 中使用伴生对象来创建单例的方式,这是一种非常常见的做法。这种方式结合了私有的主构造函数和内部对象,确保了单例的线程安全性和延迟初始化。

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

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

相关文章

Pycharm中无法使用pip安装的包问题解决方案

在终端通过pip装好包以后&#xff0c;在pycharm中导入包时&#xff0c;依然会报错。主要原因就是pip把包安装到了“解释器1”&#xff0c;但我们项目使用的是“解释器2”。具体使用的哪个解释器看项目中python解释器的配置。 解决方案一&#xff1a; Pycharm中直接安装第三方库…

pdf怎么编辑文字?了解一下这几种编辑方法

pdf怎么编辑文字&#xff1f;PDF文件的普及使得它成为了一个重要的文件格式。然而&#xff0c;由于PDF文件的特性&#xff0c;它们不可直接编辑&#xff0c;这就使得PDF文件的修改变得比较麻烦。但是&#xff0c;不用担心&#xff0c;接下来这篇文章就给大家介绍几种编辑pdf文字…

强大的处理器和接口支持BL304ARM控制器

在智慧医疗领域&#xff0c;BL304可以用于实现医疗设备的智能化、远程监控和数据交换。在智慧电力领域&#xff0c;BL304可以帮助实现电网的智能化管理&#xff0c;提升电力供应的效率。在智慧安防领域&#xff0c;BL304可以实现智能监控、智能门锁等应用&#xff0c;保障安全。…

探索未来金融科技 SCF新加坡举办启动盛会

金融科技的热潮涌向新加坡&#xff0c;令人瞩目的SCF金融公链启动会于8月13日隆重举行。这场盛宴不仅为金融科技领域注入了新的活力&#xff0c;更为广大投资者、合作伙伴以及热衷区块链发展的人士提供了一次宝贵的交流机会。 在SCF金融公链启动会上&#xff0c;William Thomps…

re学习(36)看雪CTF 2017 -Crackme

百度网盘已收集&#xff0c;需要回顾在文件夹【CTF题库收集】查看即可 刚开始先运行一下 这是一道crackme类型题目&#xff0c;是一道看雪CTF上的竞赛题&#xff0c;用OD进行分析一下。 刚开始用的是IDA分析&#xff0c;分析了半天也没有看出来什么&#xff0c;然后就在网上搜…

神经网络与卷积神经网络

全连接神经网络 概念及应用场景 全连接神经网络是一种深度学习模型&#xff0c;也被称为多层感知机&#xff08;MLP&#xff09;。它由多个神经元组成的层级结构&#xff0c;每个神经元都与前一层的所有神经元相连&#xff0c;它们之间的连接权重是可训练的。每个神经元都计算…

CAD关于在别人图纸上设计点位信息的办法【推荐】

背景&#xff1a; cad中有时候需要在客户的底图上进行设计&#xff0c;如何避免客户的底图影响你的内容呈现呢&#xff0c;就是把他原有的图纸进行“灰色话”&#xff0c;这样你的图层颜色就是都是展示出来了。 1.如何“灰话”呢 步骤&#xff1a; 1.图层特性---选中你使用的…

昨天面试的时候被提问到的问题集合(答案)

1、vue的双向绑定原理是什么&#xff1f;里面的关键点在哪里&#xff1f; Vue的双向绑定原理是基于Object.defineProperty或者Proxy来实现的&#xff0c;其关键点在于数据劫持&#xff0c;即对数据的读取和修改进行拦截&#xff0c;在数据发生变化时自动更新视图 2、实现水平垂…

Python读取遥感影像并计算NDVI指数

Python读取遥感影像并计算NDVI指数 先附上源码 读取的遥感影像数据需要先进行预处理 from osgeo import gdal import numpy as np import pandas as pd import os np.seterr(divideignore, invalidignore)class Grid:# # 1. 函数1 read_tiff读取影像# def read_tiff(self…

element中Notification组件(this.$notify)自定义样式

1、自定义样式效果 2、vue代码 this.notifications this.$notify({title: ,dangerouslyUseHTMLString: true,duration: obj.remindMethod3 ? 0:4500,customClass: notify-warning,offset: 50,showClose: false,message: this.$createElement("div",null,[this.$…

五指山下500年

工作中的困难 在工作中&#xff0c;我曾经遇到一件事情让我有强烈的情绪波动。那是一次团队内部分配任务的时候&#xff0c;我遇到了一个非常棘手的问题。 我需要在几个团队成员之间分配任务&#xff0c;但是我不知道如何分配才能让每个人都满意。我知道&#xff0c;如果任务…

微服务-sentinel详解

文章目录 一、前言二、知识点主要构成1、sentinel基本概念1.1、资源1.2、规则 2、sentinel的基本功能2.1、流量控制2.2、熔断降级 3、控制台安装3.1、官网下载jar包3.2、启动控制台 4、项目集成 sentinel4.1、依赖配置4.2、配置文件中配置sentinel控制台地址信息4.3、配置流控4…

美国陆军网络司令部利用人工智能增强网络攻防和作战决策能力

源自&#xff1a; 奇安网情局 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参考和探讨&#xff0c;并不意味着支持其观点或证实其内容的真实性。版权归原作者所有&#xff0c;如转载稿涉及版权等问题&#xff0c;请立即联系我们删除。 “人工智能技术与咨询…

零侵入,零改造,模拟人的“统计数字员工”成就新时代智能普查

“您好&#xff0c;我们是余杭区经济普查员&#xff0c;这是第五次全国经济普查告知书。”近期&#xff0c;小编陆陆续续看到了许多普查人员的辛勤身影。 啥是第五次全国经济普查&#xff1f; 第五次全国经济普查是一项重大国情国力调查&#xff0c;主要目的是全面调查我国第…

护眼灯什么价位的好?有什么性价比的台灯吗

台灯是卧室和书房必备的家用电器之一&#xff0c;现在市场上销售的台灯种类琳琅满目&#xff0c;样式让人眼花缭乱&#xff0c;价格和质量又参差不齐&#xff0c;再加上口若悬河的销售人员为产品做广告的误导&#xff0c;如果事先没有做足功课&#xff0c;盲目地去挑选一台适合…

Kind创建本地环境安装Ingress

目录 1.K8s什么要使用Ingress 2.在本地K8s集群安装Nginx Ingress controller 2.1.使用Kind创建本地集群 2.1.1.创建kind配置文件 2.1.2.执行创建命令 2.2.找到和当前k8s版本匹配的Ingress版本 2.2.1.查看当前的K8s版本 2.2.2.在官网中找到对应的合适版本 2.3.按照版本安…

分库分表篇-2.4 springBoot 集成Mycat(1.6) 分库分表,读写分离,分布式事务

文章目录 前言一、分库分表&#xff1a;二、读写分离&#xff1a;2.1 读写分离的实现&#xff1a;2.2 主从延迟&#xff1a;2.2.1 主从延迟造成的问题&#xff1a;2.2.2 主从延迟的原因&#xff1a;2.2.3 主从延迟的解决方案&#xff1a;2.2.3.1 db 层面&#xff1a;2.2.3.2 程…

苹果手机QQ聊天记录怎么恢复?不容错过的3个好方法!

之前把很久不用的QQ给卸载了&#xff0c;但是现在突然想起来里面有很重要的聊天记录&#xff0c;友友们&#xff0c;有什么办法能够帮我找回聊天记录吗&#xff1f; 随着微信的崛起&#xff0c;现在很多人已经不怎么使用QQ了&#xff0c;因此很多小伙伴都把QQ卸载了。但是卸载后…

BST55电子式流量传感器

原理、 结构 基于热式原理&#xff0c; 在封闭的探头内包含两个电阻&#xff0c; 其中一个被加热作为探 测电阻&#xff0c; 另一个未被加热作为基准电阻&#xff0c; 当介质流动时&#xff0c; 加热电阻 上的 热量被带走&#xff0c; 电阻值被改变&#xff0c; 两个电阻差值被…

分库分表篇-2.2 Mycat-分片规则

文章目录 前言一、Mycat table的分片&#xff1a;二、常用分片规则&#xff1a;2.1 id 范围分片&#xff1a;2.2 id 取模分片&#xff1a;2.3 按照枚举值 分片&#xff1a;2.4 一致性hash hash 环&#xff1a;2.5 ER 分片&#xff1a;2.6 库内分表&#xff1a;2.7 全局表&#…