通俗理解Kotlin及其30大特性

kotlin

通俗理解Kotlin及其30大特性

文章目录

  • 通俗理解Kotlin及其30大特性
    • 前言
      • 背景
      • 编译&运行
      • 字节码对比
    • Java VS Kotlin
      • 变量/常量
        • 类型声明
        • 变量初始化
        • 空安全特性
      • 函数
        • 函数声明
        • 函数参数
        • 函数可变参数
        • 局部函数
        • 函数/属性/操作符的扩展
        • 函数/属性的引用
        • 操作符重载
        • Lambda 表达式
        • 数组/List/Map/元组
      • 控制表达式
        • if/when
        • for/while
        • try-catch
        • 位运算
        • 类的定义/构造/继承
        • 类的访问修饰符
        • 数据类
        • 类的别名
    • 协程
    • 总结
      • 在AOSP中部分使用
      • 优缺点比较

前言

Kotlin是Jetbrain公司发明的编程语言之一,指在替换java。恰好Google此前和SUN公司因为java闹得打官司,所以Jetbrain机智地将Kotlin推荐给了Google Android。目前来看Kotlin在Android应用开发中起到了不错的效果。

背景

Kotlin的特色,引用官网说明:

image-20240218113127156

编译&运行

本质上,kotlin语言经过kotlin编译器也是编译成java字节码,可以运行在JVM虚拟机上。

由于多了一道转化工序,所以一般来说,Kotlin的编译时间会更长一些,产生的编译文件也大一些。

在这里插入图片描述

字节码对比

可以使用Android Studio/IDEA的工具查看Kotlin的字节码:

  • 点击菜单栏 -> Tool -> Kotlin -> Show Kotlin Bytecode,查看生成的Java字节码

  • 还可以点击顶部的"Decompile"按钮查看翻译后的Java代码

java 源码:

package com.xxxx.java;

public class SDK {
    public static int addSum(int a, int b) {
        System.out.println("run in java sdk!");
        return a+b;
    }
}

java 字节码:

// class version 65.0 (65)
// access flags 0x21
public class com/xxxx/java/SDK {

  // compiled from: SDK.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/xxxx/java/SDK; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static addSum(II)I
   L0
    LINENUMBER 5 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "run in java sdk!"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 6 L1
    ILOAD 0
    ILOAD 1
    IADD
    IRETURN
   L2
    LOCALVARIABLE a I L0 L2 0
    LOCALVARIABLE b I L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2
}

kotlin 源码:

package com.xxxx.kotlin

class SDK {

}

fun addSum(a:Int, b:Int):Int {
    println("run in kotlin sdk!")
    return a+b;
}

kotlin字节码:

// ================com/xxxx/kotlin/SDK.class =================
// class version 52.0 (52)
// access flags 0x31
public final class com/xxxx/kotlin/SDK {

  // compiled from: SDK.kt

  @Lkotlin/Metadata;(mv={1, 9, 0}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0003"}, d2={"Lcom/xxxx/kotlin/SDK;", "", "()V", "KotlinStudy"})

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/xxxx/kotlin/SDK; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1
}


// ================com/xxxx/kotlin/SDKKt.class =================
// class version 52.0 (52)
// access flags 0x31
public final class com/xxxx/kotlin/SDKKt {

  // compiled from: SDK.kt

  @Lkotlin/Metadata;(mv={1, 9, 0}, k=2, d1={"\u0000\n\n\u0000\n\u0002\u0010\u0008\n\u0002\u0008\u0003\u001a\u0016\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00012\u0006\u0010\u0003\u001a\u00020\u0001\u00a8\u0006\u0004"}, d2={"addSum", "", "a", "b", "KotlinStudy"})

  // access flags 0x19
  public final static addSum(II)I
   L0
    LINENUMBER 8 L0
    LDC "run in kotlin sdk!"
    ASTORE 2
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 2
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L1
    LINENUMBER 9 L1
    ILOAD 0
    ILOAD 1
    IADD
    IRETURN
   L2
    LOCALVARIABLE a I L0 L2 0
    LOCALVARIABLE b I L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 3
}

【java字节码 vs kotlin字节码】

image-20240220170229919

核心函数的字节码不变,在形式上稍微有调整。

Java VS Kotlin

变量/常量

类型声明

Java:

  • 使用关键字 intString 等来声明变量类型,例如 int num = 10;
    private static void test1() {
        int num=10;
        System.out.println("what's type of num?"+getType(num));
        String str="Hello, world!";
        System.out.println("what's type of str?"+getType(str));

        final int N=10;
        //N=11;
        System.out.println("N="+N);
    }

Kotlin:

  • 使用关键字 varval 来声明变量,例如 var num: Int = 10val name: String = "Kotlin"

  • 默认支持局部变量类型推断,使用关键字 valvar 声明变量

  • var是可变变量,val一旦赋值不可再变,相当于javafinal

fun test1(){
    var num = 10
    println("what's type of num?${num::class.java.typeName}")

    var str = "Hello, world!"
    println("what's type of str?" + getType(str))

    val N = 10
    //N = 11
    println("N=$N")

    //const val PI = 3.14

    println(PI)

    val a: Int = 10
    val b: Long = a.toLong()
    println("what's type of b? $b-->" + getType(b))
}

Kotlin使用关键字 const(只能用于顶层和对象声明)和 val(只读变量)来声明常量,

const 只能修饰属性(类属性、顶层属性),不能用于局部变量,再编译期间定下来,所以它的类型只能是 String 或基本类型。

例如:

const val PI = 3.14
val name: String = "Kotlin"

Kotlin数据类型转换方式更为简洁,例如:

val a: Int = 10
val b: Long = a.toLong()
变量初始化

lateinit 是一种延迟初始化方式,必须在使用前初始化,例如:

lateinit var name: String
fun init() {
    name = "Kotlin"
}

lazy 是一种懒加载方式,会在第一次访问时初始化,例如:

val name: String by lazy {
    println("Initializing")
    "Kotlin"
}

lateinit varby lazy都可以推迟初始化。

lateinit var只是在编译期忽略对属性未初始化进行检查,何时初始化还需开发者自行决定。

by lazy在被第一次调用的时候能自动初始化,做到了真正的延迟初始化的行为。

空安全特性

Java:不支持空安全特性,需要手动判断 null 值。

private static void test2() {
        String str=null;
        System.out.println(str);
        if ( str != null) {
         	System.out.println(str.substring(0,1));
        }
}

Kotlin:支持空安全特性,使用 ? 来标记可为空的类型,例如 var name: String? = null

var str: String? =null;
println(str)
println(str?.substring(0,1))
println(str?.length) // 如果 str 不为 null,返回 str 的长度,否则返回 null

此外,Kotlin还支持非空断言,使用 !! 运算符,相当于回归java设计,例如:

println(str!!.length) // 如果 str 不为 null,返回 str 的长度,否则抛出 NullPointerException

运行时会报错:

Exception in thread "main" java.lang.NullPointerException
	at com.xxxx.kotlin.KotlinMainTestKt.test2(KotlinMainTest.kt:163)
	at com.xxxx.kotlin.KotlinMainTestKt.main(KotlinMainTest.kt:16)

Elvis 运算符是一种处理空值的方式,可以指定一个默认值,例如

val str: String? = null
val length = str?.length ?: 0 // 如果 str 不为 null,返回 str 的长度,否则返回 0

Kotlin:安全类型转换是一种转换类型的方式,可以避免类型转换异常,例如:

val str: Any = "Kotlin"
val length = (str as? String)?.length ?: 0

函数

函数声明

Java:使用关键字 void 来声明函数的返回类型,例如 public void printName(String name) {}

    private static String test3() {
        return "String";
    }

Kotlin:使用关键字 fun 来声明函数,例如 fun printName(name: String) {}

private fun test3(): String {
    return "String"
}

此外,

  • Kotlin调用静态方法,无需带上包名,可以直接调用,这一点体现了kotlin的静态性。
  • Kotlin函数调用,也无须分号结尾。
函数参数

Java:不支持函数的默认参数。

    private static void test4(String name, Boolean isMale) {
        System.out.println("name="+name+", isMale="+isMale);
    }

Kotlin:支持函数的默认参数,例如 fun printName(name: String, isMale: Boolean = true) {}

test4("haha")

fun test4(name: String, isMale: Boolean = true) {
    println("name=$name, isMale=$isMale")
}

此外,类的构造函数也支持默认参数:

class Person(val name: String = "Kotlin", val age: Int = 20)

Kotlin:具名参数是一种通过名称来指定函数参数的方式,可以提高代码可读性,例如:

fun printPerson(name: String, age: Int) {
    println("Name: $name, Age: $age")
}
printPerson(name = "Kotlin", age = 20)
fun main(){
    test4("kotlin",false)
    test4("haha")                         //默认参数
    test4( isMale = false, name="Lucas")  //具名参数
}

fun test4(name: String, isMale: Boolean = true) {
    println("name=$name, isMale=$isMale")
}
函数可变参数

Java:使用 ... 来声明可变参数,例如 public void printNames(String... names) {}

    private static void test5(String... names) {
        for (int i = 0; i < names.length; i++) {
            System.out.println(names[i]);
        }
    }

Kotlin:使用关键字 vararg 来声明可变参数,例如 fun printNames(vararg names: String) {}

fun test5(vararg names: String) {
    for ( name in names){
        println(name)
    }
}
局部函数

函数中仍然可以嵌套函数,对于函数内代码块频繁调用的情况有用。

fun test6() {
    fun sum(a:Int, b:Int): Int {
        fun multiply(c:Int, d:Int): Int{
            return c*d
        }
        return multiply(a, a)+multiply(b, b);
    }
    // 平方和
    println(sum(1,2))
}
函数/属性/操作符的扩展
  • 扩展函数是一种将函数添加到现有类中的方式
  • 扩展属性是一种将属性添加到现有类中的方式
val String.lastChar: Char
    get() = get(length - 1)
val String.pai: String
    get() = "3.1415926"
val String.isEmail: Boolean
    get() = this.matches(Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"))

fun test7() {
    fun String.addHello() = this + ", Hello!"

    println("Lucas".addHello());
    println("Lucas".lastChar);
    println(String().pai);
    println("lucas.deng@xxxx.com".isEmail);
}
  • 扩展运算符是一种将数组或集合打散为参数列表的方式,例如:
fun sum(a: Int, b: Int, c: Int) = a + b + c
val list = listOf(1, 2, 3)
val result = sum(*list.toIntArray())
函数/属性的引用
  • 支持属性引用,可以使用 :: 运算符来引用属性

  • 支持函数引用,可以使用 :: 运算符来引用函数

fun test8() {
    class Person(val name: String) {
        fun printName() {
            println(name)
        }
    }
    val person = Person("Kotlin")
    val nameProperty = Person::name
    println(getType(nameProperty))
    println(nameProperty.toString())
    val name = nameProperty.get(person)
    println(name)

    fun printName(name: String) {
        println(name)
    }
    val namePrinter = ::printName
    namePrinter("Kotlin")

    val c= String::class
    println(c)

    val d= String::toString
    println(d("abc"))

    val e= String::equals
    println(e("abc", "abc"))

}
操作符重载

不是所有操作符都支持重载,支持的操作符主要是运算类的。

表达式翻译为
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
a..ba.rangeTo(b)
a..<ba.rangeUntil(b)
fun test9() {
    data class Point(val x: Int, val y: Int) {
        operator fun plus(other: Point) = Point(x + other.x, y + other.y)
        operator fun minus(other: Point) = Point(x - other.x, y)

    }

    val p1 = Point(1, 2)
    val p2 = Point(3, 4)

    val p3 = p1 + p2
    println(p3)

    val p4 = p2 - p1
    println(p4)

}
Lambda 表达式

Java:支持 Lambda 表达式,但写法比较繁琐。

如果只有一个显式声明的抽象方法,那么它就是一个函数接口。

java Lambda表达式只能应用于函数接口。

    private static void test12(){
        new Thread(
            () -> System.out.println("Thread run().....")
        ).start();

        Call call= (a,b)->{ return a+b; };
        System.out.println(call.plus(1,4));
    }

    static interface Call {
        int plus(int a, int b);
        // int minus(int a, int b);
    }

Kotlin:支持 Lambda 表达式,写法简洁,例如 val sum = { a: Int, b: Int -> a + b }

private fun test10() {
    Thread { println("Thread run().....") }.start()
    val sum = { a: Int, b: Int -> a + b }
    println(sum(1,4))
}

Java:使用 for 循环和 if 语句来实现过滤器。

Kotlin:使用 Lambda 表达式和过滤器函数来实现,例如 val nums = listOf(1, 2, 3, 4, 5).filter { it % 2 == 0 }

private fun test10() {
    Thread { println("Thread run().....") }.start()
    val sum = { a: Int, b: Int -> a + b }
    println(sum(1,4))

    val nums = listOf(1, 2, 3, 4, 5).filter { it % 2 == 0 }
    println(nums)
}
数组/List/Map/元组

数组: 不再使用[ ], 而是用Array类来代替掉,

List: 直接用listOf就可以进行初始化,直接用forEach就可以打印所有元素

Map: 直接用hashMapOf就可以进行初始化,直接用forEach就可以打印所有元素

元组:支持元组,使用 PairTriple 类来表示二元组和三元组。主要用于记录小量的二元/三元数据,而不必要重新定义一个类。

fun test11() {
    //数组
    val arrayEmpty = emptyArray<String>()
    val array1 = arrayOfNulls<Int>(5)
    val array2 = arrayOf(1, 2, 3, 4)
    array2.forEach {
        print(" $it")
    }
    println()

    // List
    val listEmpty = emptyList<String>()
    val nums = listOf(1, 2, 3, 4, 5)
    val sum = nums.reduce { acc, i -> acc + i }
    for (item in nums)
        print(" $item")
    println()

    val map = hashMapOf("Kotlin" to 1, "Java" to 2, "Python" to 3)
    println(map["Kotlin"])
    map["Lucas"] = 23
    println(map["Lucas"])

    for ((key, value) in map) {
        print("$key = $value, ")
    }
    println()

    map.forEach {
            (key, value) -> print("$key = $value, ")
    }
    println()

    val pair = Pair("Kotlin", 20)
    val triple = Triple("Kotlin", 20, "male")
    val (name, age) = pair
    println(pair)
    println(triple)

    val triple2 = Triple("Lucas", 27, "male")

    var arrays = arrayOf(triple,triple2)
    arrays.forEach {
        println(it)
    }
}

控制表达式

if/when

Java:

使用 if-else if-else 或 switch-case 来实现条件判断。

Kotlin:

if 表达式是有返回值的,可以用来赋值,基本可以代替三目运算符,例如:

fun test12() {
    val a = 10
    val b = 20
    //val max = a>b? a:b
    val max = if (a > b) a else b

    println(max)

    val value = 88
    if (value in 1..100) {
        println("$value")
    }

}

使用 when 表达式,例如:

fun test14( index : String): String {
     val num=10;
    when(index){
        "a"->return "A"
        "b"->return "B"
        "c"->return "C"
    }
    return when(num){
        1-> "99"
        2-> "88"
        3-> "77"
        else->"-1"
    }
}

fun test13() {
    var num=34
    when(num){
        10 -> println("10")
        23 -> println("23")
        34 -> println("OK!")
        35 -> println("35")
    }
}

不再需要break,不然又有什么坑要踩。

for/while

Kotlin:for 循环可以遍历集合、数组等对象,例如:

val list = listOf("Kotlin", "Java", "Python")
for (item in list) {
    println(item)
}

Kotlin:支持 Range 表达式,例如 val nums = 1..10

fun test15() {
    for (i in 1..9) {
        print(i)
    }
    println()

    for (i in 9..1) {
        print(i)
    }
    println()

    for (i in 9 downTo 1) {
        print(i)
    }
    println()

    for (i in 1..20 step 2) {
        print(i)
    }
    println()

    for (i in 1 until 10) {
        print(i)
    }
    println()
}

Kotlin:while 循环可以重复执行某个代码块,例如:

var i = 0
while (i < 10) {
    println(i)
    i++
}

Kotlin:do-while 循环与 while 循环类似,但是至少会执行一次,例如:

var i = 0
do {
    println(i)
    i++
} while (i < 10)
fun test16() {
    var i = 0
    while (i < 10) {
        print(i)
        i++
    }
    println()

    var j = 0
    do {
        print(j)
        j++
    } while (j < 10)
    println()

}
try-catch

Java:使用 try-catch 语句块来捕获异常。

Kotlin:不仅可以使用语句块,还能使用 try-catch 表达式来捕获异常,例如:

fun test17() {
    try {
        val str:String? = null;
        println(str!!.length)
    }catch (e:NullPointerException){
        println("please check your code!")
    }

    val len = try {
        val str:String? = null;
        println(str!!.length)
    }catch (e:NullPointerException){
        println("please check your code!")
        5
    }
    println(len)
}
位运算

Kotlin:位运算是一种对二进制位进行操作的方式,例如:

fun test18() {
    val a = 0b0101
    val b = 0b1010
    val c = a and b // 0b0000
    val d = a or b // 0b1111
    val e = a xor b // 0b1111
    val f = a.inv() // 0b1010

    println(c)
    println(d)
    println(e)
    println(f)
    println(Integer.toBinaryString(e))
    println(Integer.toBinaryString(f))
    
}

类的定义/构造/继承

最简单的类定义:

class Empty

class Anything{
}

定义Person类,并调用

open class Person //主构造Person()
{
    constructor(id: Int, name: String) {

    }

    constructor(id: Int, sex: Char) {

    }

    //主构造
    constructor() {

    }

    override fun toString(): String {
        return "abc"
    }

}
fun test19() {
    var person:Person = Person()
    var person2:Person = Person(110,'C')
    var person3:Person = Person(10086, "Lucas")
}

Java:使用关键字 extends 来实现类的继承,例如 public class Student extends Person {}

    private static void test7() {
        Student student = new Student();
        System.out.println(student);
    }

    static class Student extends Person {}

    static class Person {
        String name = "David";
        int age = 23;

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

Kotlin:使用关键字 : 来实现类的继承,例如 class Student : Person()

并且Person必须为open,定义Student类,继承至Person

class Student() : Person()
{
    // Kotlin 全部都是没有默认值的
    // Java 成员有默认值,但是方法内部没有默认值
    // lateinit 懒加载  没有赋值 就不能使用,否则报错

    lateinit var name : String
    var age: Int = 0

    override fun toString(): String {
        return "Student(name='$name', age=$age)"
    }

    constructor(n:String) : this() {
        name = n
    }

    constructor(n:String, a:Int) : this() {
        name = n
        age = a
    }


}
fun test20() {
    var student:Student = Student("Hello")
    println(student.toString())
}

实现接口:

interface Eat {
    fun EatMethod() : Boolean
}
class Student() : Person(), Eat
{
    override fun EatMethod(): Boolean {
        TODO("Not yet implemented")
    }
    
    ...
}
类的访问修饰符

Java:使用关键字 publicprivateprotecteddefault(没有修饰符)来修饰类的访问权限。

image-20240218154616640

Kotlin:使用关键字 publicprivateprotectedinternal 来修饰类的访问权限,默认为 public

image-20240218154726169

数据类

Java:不支持数据类。

	private static void test10() {
        User jack = new User("Jack", 23);
        System.out.println(jack.toString());
    }

    static class User{
        String username;
        int age;

        public User(String username, int age) {
            this.username = username;
            this.age = age;
        }

    }

Kotlin:

支持数据类,使用关键字 data 来声明,例如 data class User(val id: Int, val name: String, val sex: Char)

编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:

  • equals() / hashCode()
  • toString() 格式如 "User(name=John, age=42)"
  • componentN() functions 对应于属性,按声明顺序排列
  • copy() 函数
fun test21() {
    val user = User(99, "Lucas", 'M')

    val(myID, myName, mySex) = user.copy()
    println("myID:$myID, myName:$myName, mySex:$mySex")

    // _ 代表不接收
    val(_, myName2, _) = user.copy()
    println("myName2:$myName2")

    println(user.toString())
    val user1=user.copy()
    val user2=user.copy(name="Kotlin")
    println(user1.equals(user))
    println(user2.equals(user))
    
}
类的别名

Java:不支持类型别名。

Kotlin:支持类型别名,使用关键字 typealias 来声明,例如:

typealias Name = String
typealias MyList = List<String>
fun test22() {
    fun printName(name: Name) {}
    val list: MyList = listOf("Kotlin", "Java", "Python")
}

此外,内部类和枚举类也和java稍有不同,可以自行查阅。

协程

Kotlin中的协程可以认为是一个“线程框架”,类似于Java中的线程池Executor,类似于Android中的Handler/AsyncTask。

Kotlin 协程的最大好处在于,你可以把运行的不同线程的代码写在同一个代码块里,可以随意切。(用看起来同步的方式写出异步代码)

总结

在AOSP中部分使用

以frameworks/base/packages/SystemUI为例,kt文件有510个java文件有1220个占比达到了1/3。

find  ./frameworks/base/packages/SystemUI/src  -name "*.kt" |  wc -l
510
find  ./frameworks/base/packages/SystemUI/src  -name "*.java" |  wc -l
1220

优缺点比较

JavaKotlin
优点改进错误检测和解决的检查异常
提供详细的文档。
大量熟练的开发人员可用
大量的第 3 方库
它允许您形成标准程序和可重用代码。
它是一个多线程环境,允许您在一个程序中同时执行多个任务。
完美的表现
易于浏览的社区资料
使用 Kotlin 多平台框架,您可以提取一个通用代码库,同时针对所有这些代码库
Kotlin 提供了内置的 null 安全支持,这是一个救星,尤其是在 Android 上,它充满了旧的 Java 风格的 API。
它比 Java 更简洁、更具表现力,这意味着出错的空间更小。
提供用户友好且易于理解的编码规范
将大型应用程序划分为更小的层。
使用大量函数类型和专门的语言结构,如 lambda 表达式。
帮助开发者创建扩展功能
提供了一种非常简单且几乎自动化的方式来创建数据类
Kotlin 是一种静态类型语言,因此非常易于阅读和编写。
这种语言允许以各种方式交换和使用来自 Java 的信息。
在 Kotlin 中编写新代码将花费更少的时间。
部署 kotlin 代码并大规模维护它非常容易。
缺点由于诸多限制,不太适合 Android API 设计
需要大量手动工作,这增加了潜在错误的数量
JIT 编译器使程序相对较慢。
Java 具有较高的内存和处理要求。
它不支持像指针这样的低级编程结构。
您无法控制垃圾收集,因为 Java 不提供 delete()、free() 等函数。
开发者社区很小,因此缺乏学习材料和专业帮助。
Java 不提供可能导致错误的检查异常的功能。
编译速度比Java慢
编译的产物比java大
Kotlin 作为一种高度声明性的语言,有时它可以帮助您在相应的 JVM 字节码中生成大量样板

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

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

相关文章

css中选择器的优先级

CSS 的优先级是由选择器的特指度&#xff08;Specificity&#xff09;和重要性&#xff08;Importance&#xff09;决定的&#xff0c;以下是优先级规则&#xff1a; 特指度&#xff1a; ID 选择器 (#id): 每个ID选择器计为100。 类选择器 (.class)、属性选择器 ([attr]) 和伪…

一个服务器实现本机服务互联网化

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 一个服务器实现本机服务互联网化 前言痛点关于中微子代理实战演练搭建服务端搭建客户端服务端配置代理实现 前言 在数字世界的网络战场上&#xff0c;中微子代理就像是一支潜伏在黑暗中的数字特工队&…

PacketSender-用于发送/接收 TCP、UDP、SSL、HTTP 的网络实用程序

PacketSender-用于发送/接收 TCP、UDP、SSL、HTTP 的网络实用程序 PacketSender是一款开源的用于发送/接收 TCP、UDP、SSL、HTTP 的网络实用程序&#xff0c;作者为dannagle。 其官网地址为&#xff1a;https://packetsender.com/&#xff0c;Github源代码地址&#xff1a;htt…

Java 事件处理机制

一、快速入门 import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.awt.event.WindowListener;public class BallMove extends JFrame { //窗口MyPanel mp null…

一款高输出电流 PWM 转换器

一、产品描述 TPS543x 是一款高输出电流 PWM 转换器&#xff0c;集成了低电阻、高侧 N 沟道 MOSFET。具有所列的特性的基板上还包括高性能电压误差放大器&#xff08;可在瞬态条件下提供高稳压精度&#xff09;、欠压锁定电路&#xff08;用于防止在输入电压达到 5.5V 前启动&…

Py之ydata-profilin:ydata-profiling的简介、安装、使用方法之详细攻略

Py之ydata-profilin&#xff1a;ydata-profiling的简介、安装、使用方法之详细攻略 目录 ydata-profiling的简介 1、主要特点 2、案例应用 (1)、比较数据集、对时序数据集进行分析、对大型数据集进行分析、处理敏感数据、数据集元数据和数据字典、自定义报告的外观、不同类型…

【MATLAB源码-第144期】基于matlab的蝴蝶优化算法(BOA)无人机三维路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 ​蝴蝶优化算法&#xff08;Butterfly Optimization Algorithm, BOA&#xff09;是基于蝴蝶觅食行为的一种新颖的群体智能算法。它通过模拟蝴蝶个体在寻找食物过程中的嗅觉导向行为以及随机飞行行为&#xff0c;来探索解空间…

使用两个队列实现栈

在计算机科学中&#xff0c;栈是一种数据结构&#xff0c;它遵循后进先出&#xff08;LIFO&#xff09;的原则。这意味着最后一个被添加到栈的元素将是第一个被移除的元素。然而&#xff0c;Java的标准库并没有提供栈的实现&#xff0c;但我们可以使用两个队列来模拟一个栈的行…

十五、随机数和随机颜色

项目功能实现&#xff1a;在原图上进行每隔0.5s随机绘制不同长度不同颜色的线段(保存之前的线段)&#xff0c;在另一个画布上进行绘制随机不同长度不同颜色的线段(不保存之前的线段) 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 random.h #pragma once#i…

Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)

5、查看证书是否安装成功 方式一&#xff1a; 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项&#xff1a;Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器&#xff0c;选择操作—>查看证书&#xff0c;在搜索…

【C++精简版回顾】6.构造函数

一。类的三种初始化方式 1.不使用构造函数初始化类 使用函数引用来初始化类 class MM { public:string& getname() {return name;}int& getage() {return age;}void print() {cout << "name: " << name << endl << "age: &quo…

跨境电商消息多发脚本制作需要用到的代码!

在跨境电商的运营中&#xff0c;为了更有效地推广产品、提升品牌知名度并增强与消费者的互动&#xff0c;消息群发成为了一个重要的营销手段。 为了实现这一目的&#xff0c;许多跨境电商团队会选择制作消息多发脚本&#xff0c;通过自动化发送消息来提高效率和覆盖面&#xf…

Postman接口测试之Mock快速入门

一、Mock简介 1.Mock定义 Mock是一种比较特殊的测试技巧&#xff0c;可以在没有依赖项的情况下进行接口或单元测试。通常情况下&#xff0c;Mock与其他方法的区别是&#xff0c;用于模拟代码依赖对象&#xff0c;并允许设置对应的期望值。简单一点来讲&#xff0c;就是Mock创建…

LabVIEW多通道压力传感器实时动态检测

LabVIEW多通道压力传感器实时动态检测 介绍了一种基于LabVIEW的多通道压力传感器实时动态检测系统&#xff0c;解决压阻式压力传感器温度补偿过程的复杂度&#xff0c;提高测量的准确性。通过自动轮询检测方法&#xff0c;结合硬件检测模型和多通道检测系统设计&#xff0c;本…

ADC--模拟量转换成数字量

目录 一、ADC硬件组成七大部分&#xff1a; 二、单次转换&#xff0c;连续转换&#xff0c;不连续采样模式&#xff0c;扫描模式区别 1、举例(5种组合情况) 2、模拟看门狗中断的作用&#xff1a; 三、MCU使用ADC步骤 一、ADC硬件组成七大部分&#xff1a; ①输入电压&#…

C#知识点-14(索引器、foreach的循环原理、泛型、委托)

索引器 概念&#xff1a;索引器能够让我们的对象&#xff0c;以索引&#xff08;下标&#xff09;的形式&#xff0c;便捷地访问类中的集合&#xff08;数组、泛型集合、键值对&#xff09; 应用场景&#xff1a; 1、能够便捷地访问类中的集合 2、索引的数据类型、个数、顺序不…

【Linux】普通用户sudo失败怎么办

普通用户&#xff0c;sudo失败报错怎么办 问题分析如何解决成功 问题分析 新建的普通用户sudo失败 sudo提权&#xff0c;是以root的身份执行命令。 当我们用sudo提升权限的时候&#xff0c;这里有个问题&#xff0c;Linux会提示我们输入当前普通用户的密码——这就有点不好。…

机器人内部传感器阅读笔记及心得-位置传感器-旋转变压器、激光干涉式编码器

旋转变压器 旋转变压器是一种输出电压随转角变化的检测装置&#xff0c;是用来检测角位移的&#xff0c;其基本结构与交流绕线式异步电动机相似&#xff0c;由定子和转子组成。 旋转变压器的原理如图1所示&#xff0c;定子相当于变压器的一次侧&#xff0c;有两组在空间位置上…

华清远见嵌入式学习——驱动开发——DAY8

作业要求&#xff1a; 1.使用GPIO子系统编写LED灯驱动&#xff0c;应用程序测试 2.注册三个按键的中断&#xff0c;只需要写内核代码 需要发布到CSDN 作业答案&#xff1a; GPIO子系统&#xff1a; 代码效果&#xff1a; 应用程序&#xff1a; #include<stdlib.h> …

网页403错误(Spring Security报异常 Encoded password does not look like BCrypt)

这个错误通常表现为"403 Forbidden"或"HTTP Status 403"&#xff0c;它指的是访问资源被服务器理解但拒绝授权。换句话说&#xff0c;服务器可以理解你请求看到的页面&#xff0c;但它拒绝给你权限。 也就是说很可能测试给定的参数有问题&#xff0c;后端…