Kotlin基础(六):枚举类和扩展

news2024/11/23 3:59:43

前言

本文主要讲解kotlin枚举类和扩展


Kotlin文章列表

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


目录

在这里插入图片描述


1.1 枚举类

1.1.1 枚举类的基本用法

Kotlin中的枚举类(enum class)用于定义一组具有预定义值的常量。它们在许多情况下都很有用,例如表示一组相关的选项、状态或命名常量集合。下面是Kotlin枚举类的基本用法:

  1. 声明枚举类:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    
  2. 使用枚举值:

    val direction = Direction.NORTH
    println(direction)  // 输出: NORTH
    
  3. 比较枚举值:

    val direction = Direction.NORTH
    if (direction == Direction.NORTH) {
        println("向北")
    }
    
  4. 遍历枚举值:

    for (enumValue in Direction.values()) {
        println(enumValue)
    }
    
  5. 获取枚举值的名称:

    val direction = Direction.NORTH
    println(direction.name)  // 输出: NORTH
    
  6. 获取枚举值的序号(从0开始):

    val direction = Direction.NORTH
    println(direction.ordinal)  // 输出: 0
    
  7. 使用枚举类的方法和属性:

    enum class Direction {
        NORTH {
            override fun printDescription() {
                println("这是北方")
            }
        },
        SOUTH {
            override fun printDescription() {
                println("这是南方")
            }
        },
        EAST {
            override fun printDescription() {
                println("这是东方")
            }
        },
        WEST {
            override fun printDescription() {
                println("这是西方")
            }
        };
    
        abstract fun printDescription()
    }
    
    val direction = Direction.NORTH
    direction.printDescription()  // 输出: 这是北方
    

这些是Kotlin枚举类的基本用法。

1.1.2 为枚举值指定对应的数值

在Kotlin中,你可以为枚举值指定对应的数值。默认情况下,每个枚举值会自动分配一个从0开始递增的整数值作为其数值。然而,你也可以显式地为枚举值指定自定义的数值。下面是为枚举值指定数值的几种方式:

  1. 基本数值分配:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    

    在这种情况下,NORTH的数值为0,SOUTH的数值为1,以此类推。

  2. 自定义数值分配:

    enum class Direction(val degrees: Int) {
        NORTH(0), SOUTH(180), EAST(90), WEST(270)
    }
    

    在这个例子中,每个枚举值都有一个degrees属性来存储对应的数值。NORTH的数值为0,SOUTH的数值为180,以此类推。

  3. 使用匿名类和属性来分配数值:

    enum class Direction {
        NORTH {
            override val degrees: Int = 0
        },
        SOUTH {
            override val degrees: Int = 180
        },
        EAST {
            override val degrees: Int = 90
        },
        WEST {
            override val degrees: Int = 270
        };
    
        abstract val degrees: Int
    }
    

    在这个例子中,每个枚举值都通过匿名类来定义,并重写了degrees属性以指定数值。

你可以根据需要选择适合的方式来为枚举值指定数值。这样,你就可以在需要使用枚举值数值的地方访问这些数值。例如,对于第二个示例中的Direction枚举类,你可以通过direction.degrees来访问特定枚举值的数值。

1.1.3 枚举类的其他功能

除了基本用法外,Kotlin枚举类还提供了其他一些功能,使其更加灵活和强大。以下是一些Kotlin枚举类的其他功能:

  1. 声明方法:
    枚举类可以声明方法,可以在每个枚举值上调用这些方法。例如:

    enum class Direction {
        NORTH {
            override fun getOpposite(): Direction = SOUTH
        },
        SOUTH {
            override fun getOpposite(): Direction = NORTH
        },
        EAST {
            override fun getOpposite(): Direction = WEST
        },
        WEST {
            override fun getOpposite(): Direction = EAST
        };
    
        abstract fun getOpposite(): Direction
    }
    
    

    每个枚举值都实现了getOpposite()方法,根据当前方向返回相反的方向。

  2. 实现接口:
    枚举类可以实现接口。这使得你可以为枚举类的每个枚举值提供不同的实现。例如:

    interface Printable {
        fun print()
    }
    
    enum class Direction : Printable {
        NORTH {
            override fun print() {
                println("北方")
            }
        },
        SOUTH {
            override fun print() {
                println("南方")
            }
        },
        EAST {
            override fun print() {
                println("东方")
            }
        },
        WEST {
            override fun print() {
                println("西方")
            }
        };
    }
    
    

    在这个例子中,Direction枚举类实现了Printable接口,并为每个枚举值提供了不同的print()方法实现。

  3. 通过字符串获取枚举值:
    你可以通过枚举值的字符串名称来获取对应的枚举值。使用valueOf()函数实现这一点。例如:

    val direction = Direction.valueOf("NORTH")
    println(direction)  // 输出: NORTH
    

    这将返回枚举值NORTH

  4. 定义扩展函数和属性:
    你可以为枚举类定义扩展函数和属性,为枚举值添加额外的功能。例如:

    enum class Direction {
        NORTH, SOUTH, EAST, WEST
    }
    
    fun Direction.isVertical(): Boolean {
        return this == Direction.NORTH || this == Direction.SOUTH
    }
    
    val Direction.opposite: Direction
        get() = when (this) {
            Direction.NORTH -> Direction.SOUTH
            Direction.SOUTH -> Direction.NORTH
            Direction.EAST -> Direction.WEST
            Direction.WEST -> Direction.EAST
        }
    

    在这个例子中,isVertical()是一个扩展函数,用于判断枚举值是否为垂直方向。opposite是一个扩展属性,根据当前方向返回相反的方向。

这些是Kotlin枚举类的一些其他功能,它们使得枚举类更加灵活和可扩展。

1.2 扩展

1.2.1 扩展原生API

Kotlin提供了扩展函数和扩展属性的功能,使你能够扩展原生的API类,包括标准库和其他类库中的类。这使你能够在不修改原始类代码的情况下为这些类添加新的功能。下面是如何在Kotlin中扩展原生API的几种方法:

  1. 扩展函数:
    你可以为任何类定义扩展函数。要定义一个扩展函数,你需要在函数名前面加上接收者类型并使用点符号。例如,以下是为字符串类型扩展一个reverse()函数:

    fun String.reverse(): String {
        return this.reversed()
    }
    
    

    使用示例:

    val reversedString = "Hello, World!".reverse()
    println(reversedString)  // 输出: "!dlroW ,olleH"
    
    

    在这个例子中,我们扩展了String类,添加了一个reverse()函数,以反转字符串的顺序。

  2. 扩展属性:
    与扩展函数类似,你还可以为类定义扩展属性。要定义一个扩展属性,你可以使用get()和(可选)set()函数。以下是为Int类型扩展一个isEven属性:

    val Int.isEven: Boolean
        get() = this % 2 == 0
    
    

    使用示例:

    val number = 6
    println(number.isEven)  // 输出: true
    
    

    在这个例子中,我们扩展了Int类,添加了一个isEven属性,用于判断一个整数是否为偶数。

  3. 扩展标准库:
    Kotlin的标准库提供了许多常见类型的扩展函数和属性,使你能够以更简洁的方式处理数据。例如,标准库中的List类提供了许多方便的扩展函数,如filter()map()reduce()等,用于对列表进行操作和转换。

    val numbers = listOf(1, 2, 3, 4, 5)
    val evenNumbers = numbers.filter { it % 2 == 0 }
    val doubledNumbers = numbers.map { it * 2 }
    val sum = numbers.reduce { acc, value -> acc + value }
    
    

    在这个例子中,我们使用了filter()函数筛选出偶数,使用map()函数将每个数字乘以2,使用reduce()函数计算数字的总和。

扩展原生API使你能够根据自己的需求为现有类添加新的功能,提高代码的可读性和可维护性。请注意,扩展函数和属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

1.2.2 扩展自定义类

在Kotlin中,你不仅可以扩展原生的API类,还可以扩展自定义的类。这使你能够为自己的类添加新的功能或方法,以满足特定的需求。下面是如何在Kotlin中扩展自定义类的几种方法:

  1. 扩展函数:
    你可以为自定义的类定义扩展函数,以添加新的功能。要定义一个扩展函数,你需要在函数名前面加上接收者类型并使用点符号。例如,假设你有一个名为Person的自定义类,你可以为它添加一个greet()函数:

    class Person(val name: String)
    
    fun Person.greet() {
        println("Hello, $name!")
    }
    
    

    使用示例:

    val person = Person("John")
    person.greet()  // 输出: "Hello, John!"
    
    

    在这个例子中,我们为Person类添加了一个greet()函数,以便在实例上调用该函数时打印出问候语。

  2. 扩展属性:
    与扩展函数类似,你还可以为自定义的类定义扩展属性。要定义一个扩展属性,你可以使用get()和(可选)set()函数。以下是为Person类扩展一个age属性:

    class Person(val name: String)
    
    val Person.age: Int
        get() = 30
    
    

    使用示例:

    val person = Person("John")
    println(person.age)  // 输出: 30
    
    

    在这个例子中,我们为Person类添加了一个age属性,始终返回30。

  3. 扩展其他自定义类:
    你可以为任何自定义类定义扩展函数和属性,无论它们是你自己编写的类还是来自其他类库。只需按照相同的语法和规则创建扩展函数和属性即可。例如:

    class Rectangle(val width: Int, val height: Int)
    
    fun Rectangle.isSquare(): Boolean {
        return width == height
    }
    
    

    使用示例:

    val rectangle = Rectangle(5, 5)
    println(rectangle.isSquare())  // 输出: true
    

    在这个例子中,我们为Rectangle类添加了一个isSquare()函数,用于判断矩形是否为正方形。

扩展自定义类使你能够在不修改原始类代码的情况下为它们添加新的功能。这样可以提高代码的可读性、可维护性和灵活性。扩展函数和属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

1.2.3 成员函数冲突的解决方案

在Kotlin中,当你扩展的类和目标类具有相同名称的成员函数时,会发生函数冲突。这种情况下,编译器无法确定应该使用哪个函数。为了解决这个问题,你可以采取以下两种解决方案:

  1. 显式指定调用的函数:
    当发生函数冲突时,你可以使用类名作为限定符,显式指定调用哪个类的函数。例如,假设你有一个名为String的扩展函数toUpperCase(),但是String类本身也有一个toUpperCase()函数,你可以使用类名来调用扩展函数:

    fun String.toUpperCase(): String {
        return "Extension function"
    }
    
    fun main() {
        val str = "Hello"
        println(str.toUpperCase())         // 调用目标类的函数
        println(str.String.toUpperCase())  // 调用扩展函数
    }
    

    在这个例子中,我们通过使用类名String作为限定符,显式调用了扩展函数toUpperCase()和目标类的函数toUpperCase()

  2. 使用@JvmName注解:
    另一种解决函数冲突的方法是使用@JvmName注解为扩展函数指定一个不同的Java虚拟机名称。这样可以避免函数名称冲突。例如:

    @file:JvmName("StringUtil")
    
    package com.example.utils
    
    fun String.toUpperCase(): String {
        return "Extension function"
    }
    
    

    在这个例子中,我们使用@JvmName注解将扩展函数toUpperCase()的Java虚拟机名称设置为StringUtil.toUpperCase(),避免了与目标类的函数冲突。

    注意:@JvmName注解应该放在扩展函数所在的文件的顶部。

通过显式指定调用的函数或使用@JvmName注解,你可以解决函数冲突问题,并确保在扩展类和目标类具有相同名称的成员函数时,能够正确地调用所需的函数。

1.2.4 扩展属性

在Kotlin中,你可以通过扩展属性为类添加新的属性。扩展属性允许你为现有类添加新的属性,而无需修改其源代码。以下是如何在Kotlin中扩展属性的示例:

// 假设有一个名为Person的类
class Person(val name: String)

// 为Person类添加一个扩展属性age
val Person.age: Int
    get() = 30

fun main() {
    val person = Person("John")
    println(person.age)  // 输出: 30
}

在上述示例中,我们为Person类添加了一个扩展属性age。扩展属性的定义类似于扩展函数,但是在这种情况下,我们只需要定义get()函数来获取属性的值。

请注意以下事项:

  • 扩展属性不能有初始值,因为它们没有与之关联的字段。因此,你需要提供一个get()函数来计算属性的值。
  • 扩展属性不支持set()函数,因此它们是只读的。

与扩展函数一样,扩展属性仅在调用它们的作用域内可见,并且它们不能访问类的私有或受保护成员。

通过使用扩展属性,你可以方便地为现有类添加新的属性,从而提供更灵活的数据操作和访问方式。

1.2.5 扩展伴随对象(CompanionObject)

在Kotlin中,你可以使用扩展函数和扩展属性来扩展伴随对象(companion object)。伴随对象是与类关联的单例对象,它可以包含类级别的函数和属性。以下是如何扩展伴随对象的示例:

class MyClass {
    companion object {
        fun greet() {
            println("Hello from companion object!")
        }
    }
}

// 扩展伴随对象的函数
fun MyClass.Companion.sayHello() {
    println("Hello from extension function of companion object!")
}

fun main() {
    MyClass.greet()      // 调用伴随对象的函数
    MyClass.sayHello()   // 调用扩展函数
}

在上述示例中,我们有一个包含伴随对象的MyClass类。我们可以通过直接使用类名调用伴随对象的函数greet()

然后,我们使用扩展函数的语法来为伴随对象添加新的函数sayHello()。这样,我们可以使用伴随对象的函数和扩展函数来进行调用。

请注意以下事项:

  • 扩展伴随对象的函数或属性的定义需要使用Companion关键字作为限定符。
  • 扩展伴随对象的函数和属性可以与伴随对象内部定义的函数和属性共存,它们在调用时使用相同的语法。

通过扩展伴随对象,你可以为伴随对象添加新的功能,而无需修改原始类的源代码。这使得你可以更灵活地扩展伴随对象并为其添加额外的行为。

1.2.6 扩展的范围

在Kotlin中,扩展的范围(可见性)是受限的,扩展函数和属性只在特定的作用域内可见。以下是关于Kotlin扩展范围的几点要注意的事项:

  1. 扩展函数和属性的作用域:
    • 在顶层:你可以在文件的顶层定义扩展函数和属性,它们将在整个文件中可见。
    • 在类内部:你可以在类内部定义扩展函数和属性,它们将在类的范围内可见。
  2. 可见性限制:
    • 扩展函数和属性不能访问类的私有或受保护成员。它们只能访问类中的公共成员。
    • 扩展函数和属性不会继承给子类。只有在扩展函数或属性定义所在的作用域内才可见,无法通过继承传递给子类。
  3. 导入扩展:
    • 要使用扩展函数和属性,你需要在使用它们的文件中导入它们所在的包或文件。
    • 如果扩展函数或属性在同一个包内,你不需要导入,可以直接使用。
    • 如果扩展函数或属性在不同的包内,你需要使用import关键字导入它们。

例如,假设有以下代码:

package com.example.utils

fun String.reverse(): String {
    return this.reversed()
}

class MyClass {
    fun doSomething() {
        val str = "Hello"
        println(str.reverse())
    }
}

fun main() {
    val str = "World"
    println(str.reverse())
}

在这个例子中,reverse()扩展函数位于com.example.utils包中。在main()函数中,我们需要导入reverse()函数所在的包才能使用它。而在MyClass类的doSomething()函数中,由于在同一个包内,所以无需导入即可使用。

总结起来,扩展函数和属性的范围是局限于定义它们的作用域内。你需要正确导入扩展函数和属性所在的包或文件,才能在其他地方使用它们。另外,扩展函数和属性无法访问类的私有或受保护成员。

1.2.7 在类中使用扩展

在Kotlin中,你可以在类内部使用扩展函数和扩展属性。这样做可以为类添加额外的功能,而无需修改类的源代码。以下是如何在类中使用扩展的示例:

class MyClass {
    private val data: MutableList<String> = mutableListOf()

    fun addData(item: String) {
        data.add(item)
    }

    fun displayData() {
        println("Data: $data")
    }

    // 在类内部定义扩展函数
    fun MyClass.processData() {
        data.forEach {
            println("Processing: $it")
        }
    }

    // 在类内部定义扩展属性
    val MyClass.totalDataSize: Int
        get() = data.size
}

fun main() {
    val myObj = MyClass()
    myObj.addData("Item 1")
    myObj.addData("Item 2")
    myObj.addData("Item 3")

    myObj.displayData()              // 输出: Data: [Item 1, Item 2, Item 3]
    myObj.processData()              // 输出: Processing: Item 1, Processing: Item 2, Processing: Item 3
    println(myObj.totalDataSize)     // 输出: 3
}

在上述示例中,我们在MyClass类内部定义了一个扩展函数processData()和一个扩展属性totalDataSize。这些扩展函数和属性可以直接在类的实例上使用。

请注意以下事项:

  • 在类内部定义的扩展函数和属性可以直接访问类的私有成员。
  • 在类内部定义的扩展函数和属性只在类的实例上可见,不能在类的伴随对象或其他作用域中访问。

通过在类内部使用扩展函数和属性,你可以为类添加特定的功能,与类的其他成员一起工作,并直接在类的实例上使用它们。这样可以提高代码的可读性和可维护性,并使类的功能更加灵活。

1.2.8 调用特定类的成员函数

在Kotlin中,你可以使用限定符(qualifier)来调用特定类的成员函数。通过限定符,你可以明确指定调用哪个类的成员函数,尤其在存在函数名称冲突或多个类具有相同函数名时很有用。以下是几种使用限定符调用特定类成员函数的方法:

  1. 使用类名作为限定符:

    class MyClass {
        fun myFunction() {
            println("Hello from MyClass")
        }
    }
    
    fun main() {
        val obj = MyClass()
        obj.myFunction()     // 调用MyClass的myFunction函数
    }
    

    在这个例子中,我们通过创建MyClass的实例obj来调用它的成员函数myFunction()。通过实例对象限定符,我们明确地指定了调用的是MyClass的成员函数。

  2. 使用扩展函数:

    class MyClass {
        fun myFunction() {
            println("Hello from MyClass")
        }
    }
    
    fun MyClass.anotherFunction() {
        println("Hello from extension function")
    }
    
    fun main() {
        val obj = MyClass()
        obj.myFunction()         // 调用MyClass的myFunction函数
        obj.anotherFunction()    // 调用MyClass的扩展函数
    }
    

    在这个例子中,我们在MyClass类外部定义了一个扩展函数anotherFunction()。通过在实例对象上调用该扩展函数,我们仍然是明确指定了要调用的是MyClass的函数。

使用限定符的好处是可以避免函数名称冲突,并确保在存在多个类具有相同函数名的情况下,调用的是正确的类的函数。

需要注意的是,限定符只能用于调用类的成员函数,无法用于调用类的扩展函数。扩展函数的调用需要使用扩展函数的定义作用域来限定,而不是使用限定符。

1.2.9 扩展成员的继承

在Kotlin中,扩展函数和属性是静态解析的,它们不会被子类继承。这意味着在子类中定义相同名称的函数或属性不会覆盖或继承父类的扩展函数或属性。相反,子类会拥有自己独立的同名成员函数或属性。

让我们看一个示例来说明这一点:

open class Parent

fun Parent.printMessage() {
    println("Hello from Parent")
}

class Child : Parent()

fun Child.printMessage() {
    println("Hello from Child")
}

fun main() {
    val parent: Parent = Child()
    parent.printMessage()  // 输出: Hello from Parent
}

在这个例子中,我们有一个Parent类和一个Child类,Child类继承自Parent类。我们在Parent类中定义了一个扩展函数printMessage(),然后在Child类中定义了一个同名的函数。

当我们通过Child类的实例来调用printMessage()函数时,实际上调用的是Parent类的扩展函数。这是因为扩展函数是静态解析的,它们的调用在编译时就确定了,而不是在运行时根据实际对象的类型进行动态分派。

因此,子类无法继承或覆盖父类的扩展函数或属性。扩展函数和属性仅在定义它们的作用域内可见,并且它们不能通过继承传递给子类。

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

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

相关文章

【外设篇】I2C工作原理

目录 一、I2C 简介 二、I2C 主设备与从设备的关系 三、I2C 数据传输过程 3.1 总线空闲状态 3.2 开始位和停止位的产生 3.3 主设备处于等待状态 3.4 ACK 应答位的产生 3.5 有效的数据传输 3.6 数据的传输 总结 一、I2C 简介 I2C&#xff08;内置集成电路&#…

浏览器 html通知权限已经开了,但是还不提醒

如果您已经在Chrome浏览器中开启了HTML5通知&#xff0c;但是仍然不收到提醒&#xff0c;可能有几种可能的原因。下面是一些建议的解决方法&#xff1a; 检查浏览器设置: 确保HTML5通知在Chrome浏览器中正确启用。您可以按照以下步骤检查设置&#xff1a; 在Chrome中输入 chrom…

【Nacos源码系列】Nacos服务发现的原理

文章目录 服务发现是什么客户端服务发现服务端发现总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 上篇文章介绍了 Nacos服务注册的原理 &#xff0c;本篇文章将从客户端和服务端的…

微服务保护——Sentinel【实战篇二】

一、线程隔离 &#x1f349; 线程隔离有两种方式实现&#xff1a; 线程池隔离信号量隔离&#xff08;Sentinel默认采用&#xff09; 线程隔离&#xff08;舱壁模式&#xff09;&#x1f95d; 在添加限流规则时&#xff0c;可以选择两种阈值类型&#xff1a; QPS&#xff1a;…

LiveNVR监控流媒体Onvif/RTSP功能-支持无人机、IPC等设备RTMP推流转码分发H5无插件播放也支持GB28181输出

LiveNVR支持无人机、IPC等设备RTMP推流转码分发H5无插件播放也支持GB28181输出 1、无人机推流转国标2、获取RTMP推流地址2.1、RTMP推流地址格式2.2、推流地址示例 2、设备RTMP推流3、配置拉转RTMP3.1、直播流地址格式3.2、直播流地地址示例3.3、通道配置直播流地址 4、配置级联…

螺杆支撑座的加工工艺

螺杆支撑座是重要的传动元件&#xff0c;一般与滚珠螺杆搭配使用&#xff0c;滚珠螺杆的固定座可选择使用深沟球轴承C7精度&#xff0c;磨削螺杆的固定座可选择用角接触轴承的C5精度&#xff0c;C5的精度更高。 支撑侧没有精度&#xff0c;一般使用深沟球轴承&#xff0c;如果螺…

linux 系统编程-进程中的通信

目录 1 IPC 方法 2管道 2.1管道的概念 2.2 pipe 函数 2.3管道的读写行为 2.4 管道缓冲区大小 2.5 管道的优劣 2.6 FIFO 3.共享存储映射 3.1 文件进程间通信 3.2 存储映射 I/O 3.3 mmap 函数 3.4 munmap 函数 3.5 mmap 注意事项 3.6 mmap 父子进程通信 3.7 mmap …

JAVA 面试准备

这里写自定义目录标题 一、JAVA基础1.ArrayList2.HashMap3.Concurrenthashmap4.Stream5.synchronized6.线程池7.CompletableFuture8.Fork/join9.数组与链表的区别10.单例模式1.饿汉模式2.懒汉模式10.1、 为啥使用synchronized?10.2、 又为啥使用volatile?10.3、 那又又为啥用…

【MySQL进阶(一)】MySQL在Linux中的配置信息和数据备份工具

MySQL在Linux中安装的话可以看这篇博客&#xff1a;MySQL在Linux中的安装&#xff0c;我觉得总结的很好。 my.cnf 中的配置信息 当 MySQL 启动的时候&#xff0c;会从安装目录中加载软件数据&#xff0c;即使用 mysqld 工具初始化设置的 --basedir&#xff0c;会从数据目录中…

GaussDB云数据库配套工具UGO

目录 一、前言 二、数据库和应用迁移UGO定义 1、UGO定义 2、异构数据库迁移简图 三、数据库迁移的痛点 四、数据库和应用迁移UGO能力介绍 五、数据库和应用迁移UGO方案简图介绍 六、小结 一、前言 在数字化时代&#xff0c;企业面临着越来越多的数据库和应用迁移需求。…

SpringBoot解决跨域问题的几种方式

本文参考自:SpringBoot 解决跨域问题的 5 种方案!_springboot跨域问题解决方案_肥肥技术宅的博客-CSDN博客 SpringBoot解决ajax跨域问题-腾讯云开发者社区-腾讯云 跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。跨域问题本质是浏览器的一种保护机制,它的初衷…

认识C++继承

认识继承 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象程序设计的层次结构&#xff0c;体现了由…

Protobuf数据交互实战

"no one gonna make me down" 在之前呢&#xff0c;我们介绍了什么protobuf以及它的语法、数据类型。 一句老话说得好&#xff0c;"多说不练&#xff0c;假把式&#xff01;"。因此&#xff0c;本篇会选择以protobuf的语法&#xff0c;完成一个简易的通讯…

uniapp 微信小程序 自定义弹框+picker下拉选择列表+输入表单:拒绝-选择理由弹窗

效果&#xff1a; 1、template <!-- 拒绝-选择理由弹窗--> <view class"reason-popover" v-if"showReasonDialog"><view class"reason-modal"><view class"reason-title"><text>请选择拒绝理由<…

文心一言 VS 讯飞星火 VS chatgpt (64)-- 算法导论6.5 3题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;64&#xff09;-- 算法导论6.5 3题 三、要求用最小堆实现最小优先队列&#xff0c;请写出 HEAP-MINIMUM、HEAP-EXTRACT-MIN、HEAP DECREASE-KEY 和 MIN-HEAP-INSERT 的伪代码。 文心一言&#xff1a; 以下是使用最小堆实现最小…

界面控件DevExpress WPF数据编辑器组件,让数据处理更灵活!(二)

界面控件DevExpress WPF编辑器库可以帮助用户提供直观的用户体验&#xff0c;具有无与伦比的运行时选项和灵活性。WPF数据编辑器提供了全面的掩码和数据验证支持&#xff0c;可以独立使用&#xff0c;也可以作为容器控件(如DevExpress WPF Grid和WPF TreeList)中的单元格编辑器…

ubantu 安装 sudo apt install ubuntu-restricted-extras. 如何 OK

在安装的时候&#xff0c;不知道如何 Ok 使用 回车键&#xff0c;空格键 均不行&#xff0c;使用 Tab 键 &#xff0c;然后再使用 回车键。 Configuring ttf-mscorefonts-installer 答案是使用 Tab 键。

【Python】pyecharts 模块 ③ ( 使用 pyecharts 模块绘制折线图 )

文章目录 一、使用 pyecharts 模块绘制折线图1、折线图绘制过程2、完整代码示例 pyecharts 画廊网站 : https://gallery.pyecharts.org/#/ 在该网站可查看官方示例 一、使用 pyecharts 模块绘制折线图 1、折线图绘制过程 首先 , 导入 折线图 Line 对象 , 该类定义在 pyecharts…

Go http.Get不需要defer res.Body.Close()

前戏&#xff1a; go net/http包&#xff0c;必须要手动关闭嘛&#xff1f;非也。线上程序为啥协程数量直线上升&#xff0c;因为使用的姿势不对&#xff0c;请换个姿势。 干货&#xff1a; 手动关闭&#xff0c;释放资源 defer res.Body.Close() &#xff08;这是一个好习…

LeetCode[剑指Offer51]数组中的逆序对

难度&#xff1a;Hard 题目&#xff1a; 在数组中的两个数字&#xff0c;如果前面一个数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。输入一个数组&#xff0c;求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制&#xff1a; 0 < 数组…