Kotlin基础(五):类和接口

news/2024/4/28 22:19:45/文章来源:https://blog.csdn.net/a13027629517/article/details/131691313

前言

本文主要讲解类和接口,主要包括类的声明、构造器、类成员、修饰符、类的继承、接口、抽象类。


Kotlin文章列表

Kotlin文章列表: 点击此处跳转查看


目录

在这里插入图片描述


1.1 类的声明

在 Kotlin 中,类的声明使用关键字 class。下面是一个简单的类声明的示例:

class MyClass {// 类的成员变量var property1: Int = 0var property2: String = ""// 类的成员函数fun myFunction() {// 函数体}
}

在上面的示例中,MyClass 是一个简单的类,具有两个成员变量 property1property2,以及一个成员函数 myFunction。可以通过使用点符号来访问类的成员,例如 myClassInstance.property1 来访问 property1 的值,其中 myClassInstanceMyClass 类的一个实例。

除了普通的类声明之外,还可以使用一些修饰符来定义类的属性和函数的可见性。例如,private 关键字可以用于限制成员的可见性,使其只在类内部可访问。还可以使用 open 关键字来声明一个类可被继承,使用 abstract 关键字声明一个抽象类等等。

1.2 构造器

1.2.1 主构造器

在 Kotlin 中,可以使用主构造函数来声明类的主要构造逻辑。主构造函数是类头部的一部分,并跟在类名后面。

以下是一个使用主构造函数的类声明示例:

class MyClass constructor(parameter1: Type1, parameter2: Type2) {// 构造函数中的初始化逻辑init {// 使用参数进行初始化// 可以在这里执行其他的构造逻辑}// 类的成员变量var property1: Type1 = parameter1var property2: Type2 = parameter2// 类的成员函数fun myFunction() {// 函数体}
}

在上面的示例中,MyClass 使用主构造函数接收两个参数 parameter1parameter2。这些参数可以在类的成员变量中使用。在构造函数中的 init 块中,可以对成员变量进行初始化,也可以执行其他的构造逻辑。

需要注意的是,在 Kotlin 中,如果主构造函数没有任何注解或可见性修饰符,可以省略 constructor 关键字。

你还可以在主构造函数中声明默认参数,例如:

class MyClass(parameter1: Type1, parameter2: Type2 = defaultValue) {// ...
}

在这种情况下,如果调用 MyClass 构造函数时省略了 parameter2 参数,它将使用默认值 defaultValue

1.2.2 第二构造器

在 Kotlin 中,除了主构造函数,你还可以使用次要构造函数(secondary constructor)来定义类的其他构造逻辑。次要构造函数提供了额外的构造选项,使你可以使用不同的参数组合来创建对象。

以下是一个使用次要构造函数的类声明示例:

class MyClass {var property1: Int = 0var property2: String = ""constructor(parameter1: Int) {// 使用参数进行初始化property1 = parameter1}constructor(parameter1: Int, parameter2: String) {// 使用参数进行初始化property1 = parameter1property2 = parameter2}// 类的成员函数fun myFunction() {// 函数体}
}

在上面的示例中,MyClass 声明了两个次要构造函数。第一个次要构造函数接收一个 Int 类型的参数,并将其用于初始化 property1。第二个次要构造函数接收一个 Int 类型的参数和一个 String 类型的参数,并将它们用于初始化 property1property2

使用次要构造函数时,需要注意以下几点:

  • 次要构造函数必须直接或间接地调用主构造函数或另一个已存在的次要构造函数。

  • 使用 this 关键字调用同一个类的其他构造函数。

  • 在次要构造函数内部,可以执行其他的构造逻辑。 ​

1.2.3 Kotlin中的Singleton模式

在 Kotlin 中,可以使用对象声明(Object Declaration)来实现 Singleton 模式。Singleton 是一种设计模式,用于确保一个类只有一个实例,并提供全局访问点。

在 Kotlin 中,可以通过以下方式声明一个 Singleton:

object MySingleton {// 单例对象的属性和方法var property1: Int = 0var property2: String = ""fun myFunction() {// 函数体}
}

在上面的示例中,MySingleton 是一个对象声明,它具有属性 property1property2,以及函数 myFunction。这些属性和函数可以直接通过 MySingleton.property1MySingleton.property2MySingleton.myFunction() 来访问,无需创建该类的实例。

对象声明在首次访问时被延迟初始化,且只会初始化一次。因此,MySingleton 对象在应用程序生命周期中只会存在一个实例。

使用 Singleton 可以在需要共享状态或提供全局访问点的情况下非常有用。例如,日志记录器、数据库连接池等场景都可以使用 Singleton 来实现。

1.2.4 Kotlin函数中的默认参数

在 Kotlin 中,可以为函数参数提供默认值,这样在调用函数时可以选择性地省略这些参数。默认参数允许你定义函数的一组默认值,简化了函数调用并提供了更大的灵活性。

以下是一个使用默认参数的函数示例:

fun greet(name: String = "Guest", message: String = "Hello") {println("$message, $name!")
}

在上面的示例中,greet 函数有两个参数:namemessage。这两个参数都有默认值,分别为 "Guest""Hello"。如果调用该函数时没有提供这些参数的值,将使用默认值。

可以以多种方式调用带有默认参数的函数:

greet() // 使用所有参数的默认值,输出:Hello, Guest!
greet("John") // 使用默认的 message 参数值,输出:Hello, John!
greet("Alice", "Hi") // 提供所有参数的值,输出:Hi, Alice!

注意,如果需要仅为某些参数提供值而保留其他参数的默认值,可以使用命名参数来显式指定参数的值:

greet(message = "Hey", name = "Bob") // 使用命名参数,输出:Hey, Bob!

通过默认参数,可以在函数定义时提供合理的默认值,从而简化函数调用并为调用者提供更大的灵活性。

1.2.5 创建类的实例

在 Kotlin 中,可以使用 valvar 关键字来创建类的实例。val 用于声明一个不可变的引用,而 var 用于声明一个可变的引用。

以下是创建类实例的示例:

class MyClass {var property1: Int = 0var property2: String = ""fun myFunction() {println("Hello from MyClass")}
}// 创建类实例
val myObj = MyClass()// 访问类的属性和调用方法
myObj.property1 = 42
myObj.property2 = "Hello, World!"
myObj.myFunction()

在上面的示例中,我们首先定义了一个 MyClass 类,该类具有属性 property1property2,以及方法 myFunction。然后,我们使用 val 关键字创建一个名为 myObj 的不可变引用,并通过调用类的构造函数创建了一个 MyClass 的实例。

要访问类的属性和调用方法,我们使用点符号 (.) 来访问实例的成员。例如,myObj.property1 用于访问和设置 property1 的值,myObj.myFunction() 用于调用 myFunction 方法。

如果你希望在类实例化时初始化属性,可以在构造函数中接收参数,并在构造函数中使用它们进行初始化。例如:

class MyClass(val property1: Int, var property2: String) {fun myFunction() {println("Hello from MyClass")}
}// 创建类实例并传递参数
val myObj = MyClass(42, "Hello, World!")

在上述示例中,我们在 MyClass 构造函数中定义了 property1property2 参数,并将它们用作属性的初始化值。

1.3 类成员

1.3.1 属性的基本用法

在 Kotlin 中,类的属性用于存储对象的状态或数据。属性可以包含数据,并且可以通过 getter 和 setter 方法进行访问和修改。

以下是 Kotlin 类属性的基本用法:

class MyClass {// 可变属性var mutableProperty: String = "Initial Value"// 不可变属性val immutableProperty: Int = 42// 自定义 getter 和 settervar customProperty: String = ""get() = field.toUpperCase()  // 自定义 getter 方法set(value) {field = value.trim()  // 自定义 setter 方法}
}

在上面的示例中,MyClass 类包含了几个属性。具体说明如下:

  • mutableProperty 是一个可变属性,类型为 String,可以被修改。
  • immutableProperty 是一个不可变属性,类型为 Int,只能在对象初始化时赋值,并且不能再修改。
  • customProperty 是一个自定义 getter 和 setter 的属性。在 getter 方法中,我们将属性值转换为大写字母;在 setter 方法中,我们将接收到的值去除首尾空格后再赋给属性。

属性的访问方式如下:

val obj = MyClass()// 访问可变属性
println(obj.mutableProperty)  // 输出:Initial Value
obj.mutableProperty = "New Value"
println(obj.mutableProperty)  // 输出:New Value// 访问不可变属性
println(obj.immutableProperty)  // 输出:42// 访问自定义属性
obj.customProperty = "  Example  "
println(obj.customProperty)  // 输出:EXAMPLE

上述示例展示了如何访问属性以及如何使用自定义 getter 和 setter 方法。

需要注意的是,Kotlin 还提供了简化属性声明的方式,例如 var/var 代替 get/set 方法的定义,以及 field 关键字用于访问属性的幕后字段。这些是更高级的属性概念,可以在更复杂的场景中使用。

1.3.2 属性的getter和setter形式

在 Kotlin 中,类的属性可以具有默认的 getter 和 setter,也可以自定义 getter 和 setter 方法来控制属性的访问和修改行为。

以下是 Kotlin 类属性的 getter 和 setter 形式的示例:

class MyClass {var property: String = ""get() {println("Getting property value")return field}set(value) {println("Setting property value")field = value}
}

在上面的示例中,MyClass 类的 property 属性具有自定义的 getter 和 setter 方法。在 getter 方法中,我们输出一条消息并返回属性的值;在 setter 方法中,我们输出一条消息并将传入的值赋给属性的幕后字段(使用 field 关键字表示)。

属性的访问方式如下:

val obj = MyClass()obj.property = "New Value"  // 调用自定义 setter
println(obj.property)  // 调用自定义 getter

上述示例中,我们首先创建了一个 MyClass 对象 obj。然后,我们使用 obj.property 来设置属性的值,它将调用自定义的 setter 方法并输出一条消息。接下来,我们使用 obj.property 来获取属性的值,它将调用自定义的 getter 方法并输出一条消息。

需要注意的是,默认情况下,如果不提供自定义的 getter 和 setter 方法,Kotlin 会为属性生成默认的 getter 和 setter。如果属性声明为 val,则只会生成默认的 getter 方法,无法进行修改。

此外,Kotlin 还提供了一种简化的属性声明方式,即通过 val/var 关键字声明属性,而不需要显式地定义 getter 和 setter 方法。

1.3.3 保存属性值的字段

在 Kotlin 中,属性可以使用幕后字段(backing field)来保存其实际值。幕后字段是属性在内部使用的实际存储,它可以被属性的 getter 和 setter 方法访问和修改。

以下是 Kotlin 类属性使用幕后字段的示例:

class MyClass {var property: String = ""get() {println("Getting property value")return field}set(value) {println("Setting property value")field = value}
}

在上面的示例中,MyClass 类的 property 属性使用 field 作为幕后字段。在 getter 方法中,我们使用 field 来访问属性的实际值;在 setter 方法中,我们使用 field 来修改属性的实际值。

属性的访问方式如下:

val obj = MyClass()obj.property = "New Value"  // 调用自定义 setter
println(obj.property)  // 调用自定义 getter

上述示例中,我们首先创建了一个 MyClass 对象 obj。然后,我们使用 obj.property 来设置属性的值,它将调用自定义的 setter 方法并输出一条消息。接下来,我们使用 obj.property 来获取属性的值,它将调用自定义的 getter 方法并输出一条消息。

field 是 Kotlin 中预留的关键字,用于表示幕后字段。你可以根据需要为属性选择不同的幕后字段名称。如果你没有显式指定幕后字段名称,Kotlin 会根据需要自动为属性生成一个默认的幕后字段。

需要注意的是,幕后字段只在属性的自定义 getter 和 setter 方法内部可见。在类的其他地方,应该使用属性的名称来访问属性。

1.3.4 函数

在 Kotlin 中,类的成员函数用于封装对象的行为和操作。函数定义在类内部,可以访问类的属性和其他成员函数。

以下是 Kotlin 类成员函数的示例:

class MyClass {var property: String = ""fun myFunction() {println("Hello from myFunction")println("Property value: $property")}fun anotherFunction(param: Int): Int {return param * 2}
}

在上面的示例中,MyClass 类定义了两个成员函数:myFunctionanotherFunctionmyFunction 打印一条消息并访问类的属性值。anotherFunction 接收一个 Int 类型的参数 param,并返回该参数的两倍。

函数的调用方式如下:

val obj = MyClass()obj.property = "Value"
obj.myFunction()val result = obj.anotherFunction(5)
println(result)

上述示例中,我们首先创建了一个 MyClass 对象 obj。然后,我们通过 obj.property 设置属性的值。接下来,我们调用 obj.myFunction() 来执行 myFunction 函数,并输出相应的消息和属性值。最后,我们使用 obj.anotherFunction(5) 调用 anotherFunction 函数,并将返回的结果存储在 result 变量中并打印。

需要注意的是,成员函数可以访问类的属性和其他成员函数。在函数内部,可以使用 this 关键字来引用当前对象,从而访问对象的成员。

1.3.5 嵌套类

在 Kotlin 中,嵌套类是一个类被嵌套在另一个类内部的类。嵌套类在外部类的作用域之外是可见的,可以使用外部类的名称进行访问。

以下是 Kotlin 中嵌套类的示例:

class Outer {private val outerProperty: String = "Outer Property"class Nested {fun nestedFunction() {println("Nested Function")// 无法访问外部类的成员}}
}

在上面的示例中,Outer 类包含一个嵌套类 Nested。嵌套类可以访问自身的成员,但无法直接访问外部类的成员。

要访问嵌套类,可以使用外部类的名称作为限定符:

val nestedObj = Outer.Nested()
nestedObj.nestedFunction()

上述示例中,我们首先通过 Outer.Nested() 创建了一个 Nested 类的实例 nestedObj。然后,我们调用 nestedObj.nestedFunction() 来执行嵌套类的函数。

需要注意的是,嵌套类和内部类(使用 inner 关键字声明的类)是不同的概念。嵌套类不持有对外部类实例的引用,而内部类可以访问外部类的成员并持有对外部类实例的引用。

1.4 修饰符(Modifiers)

在 Kotlin 中,修饰符(Modifiers)用于修改类、函数、属性和其他声明的行为和访问级别。以下是一些常用的修饰符:

  1. 访问修饰符(Access Modifiers)
    • public:默认的修饰符,对所有地方可见。
    • private:只在同一个文件内可见。
    • protected:对同一个文件和子类可见。
    • internal:对同一个模块(module)内的所有地方可见。
  2. 可见性修饰符(Visibility Modifiers)
    • public:对所有地方可见。
    • private:只在同一个类内可见。
    • protected:对同一个类和子类可见。
    • internal:对同一个模块内的所有地方可见。
  3. 继承修饰符(Inheritance Modifiers)
    • open:允许类被继承。默认情况下,类是不可继承的。
    • final:阻止类被继承,函数被重写。
  4. 重写修饰符(Override Modifiers)
    • override:标记一个函数或属性是重写父类的。必须用在子类中。
  5. 其他修饰符
    • abstract:用于抽象类和抽象函数。
    • final:用于阻止函数被重写,属性被修改。
    • const:用于标记常量,要求在编译时确定其值。

这些修饰符可以根据需要在声明中使用,以达到所需的行为和访问级别。注意,不同的修饰符适用于不同的声明类型(例如,类、函数、属性等)。

需要注意的是,在 Kotlin 中有一些修饰符是默认的(例如,public),因此在大多数情况下不需要显式地使用它们。但是,了解这些修饰符的含义和使用场景对于编写清晰、安全和可维护的代码非常重要。

1.5 类的继承

1.5.1 Kotlin类如何继承

在 Kotlin 中,类的继承通过使用冒号(:)来表示。一个类可以继承自另一个类,称为父类(或超类),并继承父类的属性和函数。

以下是 Kotlin 中类的继承的基本语法:

open class ParentClass {// 父类的属性和函数
}class ChildClass : ParentClass() {// 子类的属性和函数
}

在上面的示例中,ChildClass 是继承自 ParentClass 的子类。通过在类名后面使用冒号,后跟父类的名称,可以实现继承关系。

需要注意的是,为了允许继承,父类必须使用 open 关键字进行标记。在默认情况下,类是不可继承的(即,类是 final 的)。通过使用 open 关键字,我们可以将类标记为可继承的。

在子类中,可以访问并重写父类的属性和函数。使用 override 关键字可以重写父类的成员。在重写的函数中,可以使用 super 关键字引用父类的实现。

以下是一个示例,展示了类的继承和重写的用法:

open class Person(val name: String) {open fun introduce() {println("My name is $name.")}
}class Student(name: String, val grade: Int) : Person(name) {override fun introduce() {super.introduce()println("I'm a student in grade $grade.")}
}

在上面的示例中,Person 是一个简单的父类,Student 是继承自 Person 的子类。子类重写了父类的 introduce 函数,并使用 super.introduce() 调用了父类的实现。然后,在子类的 introduce 函数中添加了额外的打印语句。

通过以下方式使用继承和重写:

val person = Person("John")
person.introduce()  // 输出:"My name is John."val student = Student("Alice", 10)
student.introduce()  // 输出:"My name is Alice.\nI'm a student in grade 10."

在上述示例中,我们首先创建了一个 Person 对象 person,并调用其 introduce 函数。然后,我们创建了一个 Student 对象 student,并调用其 introduce 函数。注意,子类 Student 继承了父类 Person 的属性 name

1.5.2 重写方法

在 Kotlin 中,要重写父类的方法,需要在子类中使用 override 关键字。这样做可以确保子类中的方法与父类中的方法具有相同的签名,并且在运行时调用时会调用子类的方法。

以下是重写方法的基本语法:

open class ParentClass {open fun methodName() {// 父类方法的实现}
}class ChildClass : ParentClass() {override fun methodName() {// 子类方法的实现}
}

在上面的示例中,ChildClass 是继承自 ParentClass 的子类,并重写了父类中的 methodName 方法。子类中的 methodName 方法使用 override 关键字进行标记,以表示它是对父类方法的重写。

需要注意的是,父类中被重写的方法必须使用 open 关键字进行标记,以允许子类对其进行重写。而子类中的重写方法可以选择使用 override 关键字进行标记,以明确指示该方法是对父类方法的重写(尽管没有使用 override 也能进行重写,但建议使用 override 显式标记,以提高代码的可读性)。

在子类中重写父类的方法时,可以使用 super 关键字来引用父类的实现。例如,可以使用 super.methodName() 调用父类的方法。

以下是一个示例,展示了如何重写父类的方法:

open class Shape {open fun draw() {println("Drawing a shape.")}
}class Circle : Shape() {override fun draw() {super.draw()println("Drawing a circle.")}
}

在上面的示例中,Shape 是一个基类,Circle 是继承自 Shape 的子类。子类重写了父类的 draw 方法,并在子类的方法中使用 super.draw() 调用了父类的实现。然后,在子类的方法中添加了额外的打印语句。

使用重写方法的示例:

val shape: Shape = Circle()
shape.draw()

在上述示例中,我们创建了一个 Shape 类型的变量 shape,但实际上它引用的是 Circle 对象。然后,我们调用 shape.draw() 方法。由于多态性的存在,实际上调用的是 Circle 类中重写的 draw 方法。输出结果将首先打印 “Drawing a shape.”,然后打印 “Drawing a circle.”。

1.5.3 重写属性

在 Kotlin 中,可以通过重写属性来修改从父类继承的属性的行为。属性的重写需要使用 override 关键字,并且可以对父类属性的访问器(getter 和 setter)进行重写。

以下是重写属性的基本语法:

open class ParentClass {open val propertyName: Type = initial value
}class ChildClass : ParentClass() {override var propertyName: Typeget() {// 重写 getter}set(value) {// 重写 setter}
}

在上面的示例中,ChildClass 是继承自 ParentClass 的子类,并重写了父类的 propertyName 属性。子类中的 propertyName 属性使用 override 关键字进行标记,并重写了父类属性的访问器。

在重写属性的访问器中,可以自定义属性的行为,例如提供不同的值或添加额外的逻辑。

需要注意的是,与重写方法类似,父类中被重写的属性必须使用 open 关键字进行标记,以允许子类对其进行重写。而子类中的重写属性可以选择使用 override 关键字进行标记,以明确指示该属性是对父类属性的重写(尽管没有使用 override 也能进行重写,但建议使用 override 显式标记,以提高代码的可读性)。

以下是一个示例,展示了如何重写父类的属性:

open class Shape {open val description: String = "Shape"
}class Circle : Shape() {override val description: String = "Circle"
}

在上面的示例中,Shape 是一个基类,Circle 是继承自 Shape 的子类。子类重写了父类的 description 属性,并提供了不同的值。

使用重写属性的示例:

val shape: Shape = Circle()
println(shape.description)

在上述示例中,我们创建了一个 Shape 类型的变量 shape,但实际上它引用的是 Circle 对象。然后,我们打印 shape.description 属性。由于多态性的存在,实际上访问的是 Circle 类中重写的 description 属性。输出结果将是 “Circle”。

需要注意的是,重写属性的访问器也可以调用父类属性的访问器,使用 super 关键字,例如 super.propertyName

1.6 接口

在 Kotlin 中,接口(Interfaces)是一种定义行为和功能的方式,类可以实现一个或多个接口来继承接口中定义的方法和属性。接口定义了一组要求,而实现接口的类需要提供对应的实现。

以下是定义接口的基本语法:

interface InterfaceName {// 接口中的属性和方法
}

接口中可以包含属性和方法声明,但不能包含实际的实现代码。接口的属性可以是抽象的(没有初始值)或具有访问器的属性(可以有自定义的 getter 和 setter)。接口的方法可以是抽象的(没有实现体)或具有默认实现。

接口的实现使用 : 符号,类可以通过关键字 implements 或者直接通过 : 实现接口。

以下是一个简单的接口示例:

interface Printable {fun print()
}class Document : Printable {override fun print() {println("Printing document...")}
}

在上面的示例中,我们定义了一个名为 Printable 的接口,它声明了一个抽象的方法 print()。然后,我们创建了一个类 Document,它实现了 Printable 接口,并提供了对应的实现。

要注意的是,在类中实现接口的方法时,需要使用 override 关键字进行标记,以明确指示这是对接口方法的实现。

使用接口的示例:

val document = Document()
document.print()

在上述示例中,我们创建了一个 Document 类的实例,并调用了实现的 print() 方法。输出结果将是 “Printing document…”。

接口可以用于在不同的类之间建立共同的协议,并实现多态性。类可以实现多个接口,通过逗号分隔。

interface Interface1 {// ...
}interface Interface2 {// ...
}class MyClass : Interface1, Interface2 {// ...
}

1.7 抽象类

在 Kotlin 中,抽象类(Abstract Class)是一种不能被实例化的类,它可以包含抽象方法和非抽象方法。抽象类用于提供一个基类的模板,定义通用的属性和方法,但需要子类来实现其中的抽象方法。

以下是定义抽象类的基本语法:

abstract class AbstractClassName {// 抽象方法和非抽象方法
}

抽象类使用 abstract 关键字进行标记,其中包含的抽象方法没有实现体,而非抽象方法可以有实现。

子类继承抽象类时,必须提供对抽象方法的具体实现。如果子类不提供对抽象方法的实现,那么子类也必须声明为抽象类。

以下是一个简单的抽象类示例:

abstract class Shape {abstract fun calculateArea(): Doublefun printDescription() {println("This is a shape.")}
}class Circle(private val radius: Double) : Shape() {override fun calculateArea(): Double {return Math.PI * radius * radius}
}

在上面的示例中,Shape 是一个抽象类,它声明了一个抽象方法 calculateArea() 和一个非抽象方法 printDescription()。然后,我们创建了一个 Circle 类,它继承自 Shape 抽象类,并提供了对 calculateArea() 方法的具体实现。

需要注意的是,在子类中重写抽象方法时,必须使用 override 关键字进行标记,以明确指示这是对抽象方法的实现。

使用抽象类的示例:

val circle = Circle(5.0)
circle.printDescription()
val area = circle.calculateArea()
println("Area: $area")

在上述示例中,我们创建了一个 Circle 类的实例,并调用了从抽象类 Shape 继承的 printDescription() 方法。然后,我们计算了圆的面积,并将其打印出来。

抽象类是一种有助于提供代码复用和约束子类行为的工具。抽象类可以包含具体的属性和方法,以及抽象的方法,这使得抽象类可以充当一种中间层,实现通用的逻辑,并强制子类提供特定的行为。

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

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

相关文章

感受C++模版的所带来的魅力

一、泛型编程思想 首先我们来看一下下面这三个函数,如果学习过了 C函数重载 和 C引用 的话,就可以知道下面这三个函数是可以共存的,而且传值会很方便 void Swap(int& left, int& right) {int temp left;left right;right temp; }…

springboot项目target下面没有mapper.xml文件

文件结构是这个样子,mapper.xml文件在resources/mappers/fdms目录下面 通常来说, 将mapper打包到target目录下只需要在maven下面配置 <resources><resource><directory>src/main/resources</directory><filtering>true</filtering><inc…

【实战项目】c++实现基于reactor的高并发服务器

基于Reactor的高并发服务器&#xff0c;分为反应堆模型&#xff0c;多线程&#xff0c;I/O模型&#xff0c;服务器&#xff0c;Http请求和响应五部分 全局 反应堆模型 Channel 描述了文件描述符以及读写事件&#xff0c;以及对应的读写销毁回调函数&#xff0c;对应存储arg读…

ARM架构介绍

概览 Arm 架构为处理器或内核&#xff08;称为处理单元PE&#xff09;的设计提供了基础。 Arm架构已经集成到许多片上系统 (SoC) 设备中&#xff0c;比如智能手机、微型计算机、嵌入式设备、服务器甚至超级计算机。 Arm架构为软件开发人员提供了通用指令集和工作流程&#x…

爬取 2 万多张 Flickr 图片,莫纳什大学复现 10 年间日本樱花开放的时空特征

内容一览&#xff1a;近年来&#xff0c;全球气候变化形势严峻&#xff0c;由此引发的蝴蝶效应&#xff0c;正深刻地影响着人类和大自然。在这一背景下&#xff0c;收集数百甚至数千公里范围内开花模式的数据&#xff0c;了解气候变化如何对开花植物产生影响&#xff0c;成为近…

python -m 是什么命令

python -m 命令是什么意思 首先python --help 可以看到-m的含义&#xff1a;意思是将库中的python模块用作脚本去运行。 python --help 命令显示结果 python -m xxx.py 和python xxx.py 有什么区别 这是两种加载py文件的方式: 叫做直接运行&#xff08;python xxx.py&#xf…

OpenCV中的RGB与YUV转换

1 基本概念 YUV 颜色空间从模拟电视时代开始就被广泛应用于彩色图像的转换与处理。其基于一个 3x3 的矩阵&#xff0c;通过线性变换将 RGB 像素转换为一个亮度&#xff08;Luma&#xff09;分量 Y 以及两个色度&#xff08;Chroma&#xff09;分量 U 和 V。由于模拟电视存在着多…

RabbitMQ系列(28)--RabbitMQ使用Federation Queue(联邦队列)解决异地访问延迟问题

前言&#xff1a; 联邦队列可以在多个Broker节点(或者集群)之间为单个队列提供均衡负载的功能。一个联邦队列可以连接一个或者多个上游队列(upstream queue)&#xff0c;并从这些上游队列中获取消息以满足本地消费者消费消息的需求。 1、Federation Queue工作原理图 2、添加策…

ELK-日志服务【filebeat-安装使用】

目录 【1】安装Filebeat 【2】配置-测试 【3】配置使用Filebeat 【4】filebeat-收集系统文件日志 【5】配置filebeat&#xff0c;将/var/log/all.log日志采集到es集群中 【6】定制索引名称 【7】收集多个web节点的日志&#xff0c;输出到相同的索引中 【8】filebeat-收…

数据结构--栈

一、栈 数组是一种连续存储、随机访问的线性表&#xff0c;链表属于分散存储、连续访问的线性表。它们每个数据都有其相对位置&#xff0c;有至多一个直接前驱和之多一个直接后继。栈&#xff08;Stack&#xff09;和队列&#xff08;Queue&#xff09;也属于线性表&#xff0c…

twaver——树中选择子网,拓扑中显示子网里面的拓扑

twaver.network.Network.setCurrentSubNetwork ( currentSubNetwork [animate] [finishFunction] ) 将当前子网设置为指定子网&#xff0c;并且可以设置是否有动画效果&#xff0c;而且能指定设置当前子网结束后执行的动作 Parameters: currentSubNetwork twaver.SubNetwork 子…

【UT学习记录】

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 Part1&#xff1a;Mock Part2&#xff1a;PowerMock Part3:Junit 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文…

即插即用篇 | YOLOv8 引入具备跨空间学习的高效多尺度注意力 Efficient Multi-Scale Attention | 《ICASSP 2023 最新论文》

论文地址:https://arxiv.org/vc/arxiv/papers/2305/2305.13563v1.pdf 该论文展示了通道或空间注意机制在各种计算机视觉任务中产生更明显的特征表示的显著效果。然而,通过通道维度缩减来建模跨通道关系可能会在提取深度视觉表示方面带来副作用。本文提出了一种新颖高效的多尺…

ES6——Promise

promise 含义&#xff1a;异步编程解决方案 特点&#xff1a;1、状态不受外界影响&#xff0c;状态有三种&#xff1a;pending、fulfilled、rejected 2、状态不可逆&#xff0c;只能pending -> fulfilled、pending -> rejected 缺点&#xff1a;无法取消、不设置回调函…

C语言联合体

一、联合体的概念 联合 (union) 是一个能在同一个存储空间里 ( 但不同时) 存储不同类型数据的复合数据类型。 大致结构如下&#xff1a; n union foo /* 定义一个联合类型foo */ n { q int digit; q double bigfl[10]; q char letter; n }baz; /* 定义一个example类型的联合变量…

JVM (simple Version)

简介 JVM 其实就是一个Java进程 , 从操作系统申请一大块内存区域, 供 java 代码使用 . 申请出的内存 , 进一步划分 , 给出不同的用途 . JVM 内存区域划分 : 堆中存放就是 new 出来的对象. (成员变量) 栈 是用来维护方法之间的调用关系 (局部变量) 元数据区(或者叫方法区) 存放的…

计算机毕设 大数据房价数据分析及可视化 - python 房价分析

文章目录 1 课题背景2 数据爬取2.1 爬虫简介2.2 房价爬取 3 数据可视化分析3.1 ECharts3.2 相关可视化图表 4 最后 1 课题背景 房地产是促进我国经济持续增长的基础性、主导性产业。如何了解一个城市的房价的区域分布&#xff0c;或者不同的城市房价的区域差异。如何获取一个城…

自动驾驶与智能网联场地测试一体化装备应用

自动化驾驶层级与结构 L1:能够辅助驾驶员玩车某些驾驶任务制动防抱死系统 (ABS),车身电子稳定系统 (ESP)等,这些配置就是L1级别的运用。 L2:部分自动化,在L2的级别里,必须要具备的是自适应巡航系统,主动车道保持系统自动刹车辅助系统以及自动泊车系统等系统。 L3:有条件…

Qt + QR-Code-generator 生成二维码

0.前言 之前使用 libgrencode 生成二维码&#xff0c;LGPL 协议实在不方便&#xff0c;所以需要找一个 github 星星多的&#xff0c;代码简单最好 header-only&#xff0c;协议最好是 MIT 或者兼容协议而不是 GPL 或者 LPGL。 QR-Code-generator 正好符合这个要求&#xff0c…

Linux和Shell笔记-1相关概念理解

Unix和Linux关系 UNIX是最早的商业操作系统之一&#xff0c;由贝尔实验室&#xff08;AT&T Bell Laboratories&#xff09;于 1970 年代开发。UNIX 是一个多用户、多任务的操作系统&#xff0c;具有强大的命令行界面和可扩展性。 Linux 是一个开放源代码的类 UNIX 操作系统…