Kotlin基础

 

基础语法

1、包引用

和Java一样,包名称使用package声明,包的引入使用import。

package com.runoob.main

import java.util.*

如果没有指定包,默认为 default 包。

默认导入

有多个包会默认导入到每个 Kotlin 文件中:

  • kotlin.*
  • kotlin.annotation.*
  • kotlin.collections.*
  • kotlin.comparisons.*
  • kotlin.io.*
  • kotlin.ranges.*
  • kotlin.sequences.*
  • kotlin.text.*

2.函数

函数使用fun关键字定义

fun sum(a:Int, b:Int) : Int {
    return a + b
}

sum是函数名称,括号中定义函数的参数和参数类型,a为参数名,a:Int,Int为参数a的数据类型。

kotlin中参数的定义是  参数名:参数类型的方式。

括号后边的 : Int 定义函数返回值类型。此函数的返回值为 Int。

注意:与Java不同,kotlin行结尾不需要使用分号。

2.1 无返回值的函数

无返回的类型,使用 Unit。或者不需要声明

    private fun printSum(a: Int, b: Int): Unit {
        println(a + b)
    }

2.2 public 函数需要声明返回类型

如果public方法是无返回的类型,返回值可以使用Unit或者不申明。 

    public fun sum(a: Int, b: Int): Int {
        return a + b;
    }

如果返回类型是Unit,可以不用声明

public fun printSum(a:Int, b:Int) {
    println("${a} + ${}b = ${a+b}")
}

2.3 可变长参数函数

函数的变长参数可以用 vararg 关键字进行标识:

fun vars(vararg v:string){
    for(vt in v){
        print(vt)
    }
}

2.4 lambda(匿名函数)

sumLamdba是一个匿名函数,输入参数有两个,参数类型为Int和Int,->表示返回值,类型是Int。

{}中定义匿名函数的方法体。

// 测试
fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}

3 变量和常量

3.1 可变变量定义:var 关键字

var [<标识符>] : <类型> = <初始化值>

可变变量相当于Java中的普通变量。

可变变量声明和初始化的时候,可以省略类型,编译器会根据初始化值的类型作为变量的类型。

3.2 不可变变量:val关键字

val [<标识符>] : <类型> = <初始化值>

不可变变量相当于Java中final修饰的变量,值初始化以后,不允许改变。

和Java一样,变量声明和变量初始化可以不同时。

可以先声明变量,然后再进行初始化化。但是变量使用之前必须初始化。

val a: Int = 2  // 指定变量a类型是Int,并且初始化为2
val b = 2       // 根据初始化的值的类型,系统自动推断变量类型为Int
val c: Int      // 如果不在声明时初始化则必须提供变量类型
c = 2           // 明确赋值


var x = 5        // 系统自动推断变量类型为Int

3.3 常量

可以通过val定义常量。

4 注释

和Java一样,支持单行注释和多行注释。

// 单行注释

/** 
 * 多行注释
 */

与 Java 不同, Kotlin 中的块注释允许嵌套。

 

5 NULL处理机制

kotlin NULL安全机制设计,标记为可为NULL的参数/变量,在使用时要进行空判断处理,有两种处理方式:
抛出异常:参数后增加“!!”。

// 抛出空指针异常
val ages = age!!.toInt()

NULL处理:可为NULL的参数增加?,处理NULL情况

定义变量的时候,如果变量可以为NULL,声明时需要声明可为NULL

var a:String? = "abc"  // a为字符串变量,初始值为“abc”,a可以为NULL
// 不做处理返回 null
val ages1 = age?.toInt()

在函数体内,对于可为NULL的参数/变量,NULL的时不进行处理,防止出现NullPonterExceptiop

age为NULL时,直接返回NULL, ages=NULL

age不为NULL时,返回age.toInt()

如果需要定义NULL场景的处理,后面使用 : 定义为NULL的处理。

// age不为空,返回age.toInt();为空返回-1
val ages2 = age?.toInt() ?: -1

如果函数的返回值可能为NULL,定义函数的时候需要声明

/**
 * 方法parseInt的返回值可能为NULL,返回值需要声明NULL。"Int? "表示返回值类型为Int,返回值可以为 
 * NULL。使用者需要处理返回值为NULL的情况
 */
fun parseInt(str: String): Int? {
  // ...
}

 

6 类型检测和自动类型转换

判断数据类型,使用 is (相当于Java的instanceof)

if (obj is String) {
    // 这个分支内部obj自动转换为String
    return obj.length
}

7 区间表达式

区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。

for (i in 1..4) print(i) // 从1到4的循环,输出“1234”

可以使用step指定步长

// 使用 step 指定步长,第一轮为1,第二轮为1+2=3,第三轮为5
for (i in 1..5 step 2) print(i) // 输出“135”

从大到小的循环可以使用downTo

for (i in 4 downTo 1 step 2) print(i) // 输出“42”

不包括最后一个元素[1,10),排除10

// 使用 until 函数排除结束元素
for (i in 1 until 10) {   // i in [1, 10) 排除了 10
     println(i)
}

8 Kotlin基本数据类型

8.1 基本数值类型

字面常量

  • 十进制:123
  • 长整型以大写的 L 结尾:123L
  • 16 进制以 0x 开头:0x0F
  • 2 进制以 0b 开头:0b00001011
  • 注意:8进制不支持

Kotlin支持传统的数值写法:

Doubles 默认写法: 123.5, 123.5e10
Floats 使用 f 或者 F 后缀:123.5f

8.2 比较两个大小

Kotlin 中没有基础数据类型,只有封装的数字类型,你每定义的一个变量,其实 Kotlin 帮你封装了一个对象,这样可以保证不会出现空指针。数字类型也一样,所以在比较两个数字的时候,就有比较数据大小和比较两个对象是否相同的区别了。

kotlin比较大小包括比较数值地址和比较数值大小。

三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

    val a: Int = 10000
    println(a === a) // true,值相等,对象地址相等

    // 经过了装箱,创建了两个不同的对象
    val boxedA: Int? = a
    val anotherBoxedA: Int? = a

    // 虽然经过了装箱,但是值是相等的,都是10000
    println(boxedA === anotherBoxedA) //  false,值相等,对象地址不一样
    println(boxedA == anotherBoxedA) // true,值相等

8.3 类型转换

类型转换可以通过toXX()进行转换。

val b: Byte = 1 // OK, 字面值是静态检测的
val i: Int = b.toInt() // OK。不能直接将b赋值给i,因为两者类型不相同。

每种数据类型都有下面的转换放大:

toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char

8.4 位操作符

shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向

8.5 字符类型

和Java不一样,kotlin字符不能和数字直接操作,字符需要通过单引号包括起来

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of char range")
    return c.toInt() - '0'.toInt() // 通过toInt显式转换为数字
}

8.6 布尔类型

和Java一样,布尔类型Boolean,有两个值:true和false

布尔运算逻辑与 &&   逻辑或 ||   逻辑非 !

8.7 数组

kotlin创建数组,有两种方式。

arrayOf和Array工厂模式

//[1,2,3,4]
val a = arrayOf(1, 2, 3,4)
//[0,2,4]  3个元素,第i个元素的值为 (i* 2)
val b = Array(3, { i -> (i * 2) })

元素的访问,和Java一样,通过下标访问,可以使用a[i]的方式。

8.8 字符串

和Java一样,kotlin中String也可以通过字符遍历。

Kotlin 支持三个引号 """ 扩起来的字符串,支持多行字符串,

fun main(args: Array<String>) {
    val text = """
    这是多行字符串
    第二行多行字符串
    """
    println(text)   // 输出有一些前置空格
}

8.9 字符串模板

字符串可以包含模板表达式 ,即一些小段代码,会求值并把结果合并到字符串中。 模板表达式以美元符($)开头,由一个简单的名字构成:

类型与Java的格式化输出

var a = 5;
var b = 7;
var str = "$a + $b = ${a+b}"

原生字符串和转义字符串内部都支持模板。 如果你需要在原生字符串中表示字面值 $ 字符(它不支持反斜杠转义)

    val price = """
    ${'$'}9.99
    """
    println(price)  // 求值结果为 $9.99

9 条件控制

9.1 IF表达式

if表达式和Java使用相同

        var a = 5
        // 测试IF表达式
        if (a > 60) {
            println("我及格了")
        } else {
            println("真糟糕,我没及格")
        }

9.2 When表达式

when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。
when 既可以被当做表达式使用也可以被当做语句使用。如果它被当做表达式,符合条件的分支的值就是整个表达式的值,如果当做语句使用, 则忽略个别分支的值。

类似于Java的switch-case,不过分支判断可以支持表达式。

        // 测试WHEN表达式
        var x = 88
        when (x) {
            in 0 until 60 -> println("还是没及格,加油呀")
            in 60 until 80 -> println("及格了")
            in 80 until 90 -> println("良好,还可以")
            in 90..100 -> println("你真优秀")
            else -> println("无效分数")
        }

10 循环语句

kotlin循环有for循环和while循环

        val items = listOf("大毛", "二毛", "明明")
        for (item in items) {
            println(item)
        }

也可以根据索引进行循环遍历

        // 根据索引循环遍历
        for (index in items.indices) {
            // items[index]按照索引获取元素值,或者使用items.get(index)
            println("item $index is ${items[index]}")
        }

和Java一样,kotlin也支持迭代器

        // 使用迭代器循环遍历
        var it = items.iterator()
        while (it.hasNext()) {
            println("item ${it.next()}")
        }

do...while循环,与while循环类似,不过至少执行一次。

        // 测试do...while循环
        println("===测试do...while循环===")
        var i = 0
        do {
            println("第 ${i + 1} 次循环 i=$i")
            i++
        } while (i < 5)

 

11 类和对象

11.1 类成员(类属性)

类的属性可以用关键字 var 声明为可变的,否则使用只读关键字 val 声明为不可变。

11.2 类的成员的set和get方法

/**
 * 基类
 *
 * @author zhouronghua
 * @time 2021/6/7 6:11 PM
 */
open class Person {

    /**
     * 姓名
     */
    var name:String = ""

    /**
     * 年龄
     */
    var age:Int = 0

    /**
     * 性别
     */
    var sex:String = ""
        get() = field  // filed指示为当前属性sex
        set(value) {
            field = value
        }

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

    /**
     * 类方法:toString
     */
    override fun toString(): String {
        return "Person(name='$name', age=$age, sex='$sex')"
    }
}

kotlin提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器

 

11.3 主构造函数

主构造函数不能包含任何代码,初始化代码可以放在初始化方法init中。

class Person constructor(firstName: String) {
    init {
        println("FirstName is $firstName")
    }
}

class A 修饰符 constructor(当前类的属性) { }

如果主构造函数没有任何修饰符,可以省略 constructor 关键字,如果没有任何属性,可以 省略小括号()

11.4 次构造函数

次构造函数 使用 constructor 关键字声明。如果有柱构造函数,次构造函数必须调用主构造函数(直接或者间接调用)

11.5 类方法

类方法采用fun定义

12 密闭类(sealed)

密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。

声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。

sealed不能修饰interface, abstract class。

/**
 * 密闭类测试
 *
 * @author zhouronghua
 * @time 2021/6/10 8:43 AM
 */
sealed class Gender(val type: String) {

    /**
     * 男人
     */
    class Man() : Gender("男人")

    /**
     * 女人
     */
    class Woman() : Gender("女人")

}


    /**
     * 测试密封类
     */
    private fun testSealedClass() {
        println("===测试密闭类===")
        var man = Gender.Man()
        println("密闭类 ${man.type}")
    }

Gender的子类,只有Man和Woman。其他的类不能继承Gender。

使用密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了。

    /**
     * 打印性别
     */
    private fun printGender(gender: Gender) {
        // 密闭类判读的时候只需要枚举子类情形,不必要处理else
        when (gender) {
            is Gender.Man -> println("是个男人")
            is Gender.Woman -> println("是个女人")
        }
    }

13 数据类

13.1 数据类特性:

  • 主构造函数至少包含一个参数。
  • 所有的主构造函数的参数必须标识为val 或者 var ;
  • 数据类不可以声明为 abstract, open, sealed 或者 inner;
  • 数据类不能继承其他类 (但是可以实现接口)。

13.2 数据类属性

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

  • equals() / hashCode()
  • toString() 格式如 "User(name=John, age=42)"
  • componentN() functions 对应于属性,按声明顺序排列
  • copy() 函数

    /**
     * 数据类
     */
    data class User(var name:String, val gender:String) {
        /**
         * 注册时间
         */
        var registerTime: String = ""
    }


    // 数据类自动实现toString()。User(name=jakson, gender=男)
    // 更新注册时间
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        val date = LocalDate.now()
        val fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd")
        val dateStr = date.format(fmt)
        println("dateStr $dateStr")
        jakson.registerTime = dateStr
    }
    println("jakson info: ${jakson.toString()}")

数据类根据主构造函数的属性自动实现了toString方法。因此能够直接输出toString内容。

jakson.toString不会打印注册时间,因为注册时间属性不在主构造函数中。

因为数据类自动实现了toString,打印$jackson的内容和打印$jakson.toString内容相同。

        // 测试数据类拷贝
        println("===测试数据类拷贝===")
        var peter = jakson.copy(name = "peter")
        println("peter info: ${peter} registerTime:${peter.registerTime}")

peter info: User(name=peter, gender=男) registerTime:

我们看到jakson的注册时间属性没有拷贝到peter,因为registerTime不是主构造函数的属性。

14 枚举类

14.1 枚举类定义

枚举类最基本的用法是实现一个类型安全的枚举。

枚举常量用逗号分隔,每个枚举常量都是一个对象。枚举类采用enum定义

/**
 * 枚举类:形状
 *
 * @author zhouronghua
 * @time 2021/6/9 11:26 AM
 */
enum class Shape(val desc: String) {
    /**
     * 椭圆
     */
    OVAL("椭圆"),

    /**
     * 圆形
     */
    CIRCLE("圆形"),

    /**
     * 矩形
     */
    RECTANGLE("矩形");

}

14.2 枚举类内置成员

枚举类包含内置成员name和ordinal。参考Enum.kt

name对应枚举类常量名称。

        // 测试枚举类
        println("===测试枚举类===")
        var shape = Shape.CIRCLE
        // 图形 CIRCLE ordinal 1
        println("图形 ${shape.name} ordinal ${shape.ordinal}")

14.3 枚举类对象获取

枚举类对象可以通过valueOf获取

        // 根据枚举类名称获取枚举类
        shape = Shape.valueOf("OVAL")
        // 打印枚举类名称(OVAL)
        println("获取的枚举类型对象为 ${shape.name}  ordinal ${shape.ordinal}")

枚举类名称没有匹配上的时候会抛出异常

        // 枚举类名没有匹配上的话则会抛出异常
        shape = Shape.valueOf("BOX")
        println("获取的枚举类型对象为 ${shape.name}")

14.4 枚举类遍历

可以通过enumValues获取枚举类常量列表;

通过enumValueOf("RECTANGLE")查找对应的枚举类常量

        // 枚举类常量遍历
        println("===枚举类常量遍历===")
        var items: Array<Shape> = enumValues<Shape>()
        for (item: Shape in items) {
            println("枚举元素 ${item.name}")
        }
        // 通过枚举名称查找枚举类常量
        println("===查找枚举类===")
        var child: Shape = enumValueOf("RECTANGLE")
        println("枚举元素 ${child.name}")

15 嵌套类

kotlin中的嵌套类,嵌套类不能访问外部类的属性,因为嵌套类实际上是一个静态内部类

嵌套类相当于Java的静态内部类,不持有外部类的对象

/**
 * 内部类举例
 *
 * @author zhouronghua
 * @time 2021/6/10 9:42 AM
 */
class Car(val model:String) {

    class Petrol() {

        fun getPetrolName() : String {
            return ""
        }
    }
}

16 内部类

内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。

/**
 * 内部类举例
 *
 * @author zhouronghua
 * @time 2021/6/10 9:42 AM
 */
class Car(val model: String) {

    /**
     * 汽油
     */
    class Petrol() {

        fun getPetrolName(): String {
            return ""
        }
    }

    /**
     * 车轮
     * 说明: 内部类。可以访问外部类对象
     */
    inner class Wheel(val brand: String) {

        /**
         * 打印车轮信息
         */
        fun printWheel() {
            // 能够访问到外部类的对象实例
            println("$model wheel is $brand")
        }

    }
}

17 匿名内部类

使用对象表达式来创建匿名内部类:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        view.findViewById<Button>(R.id.button_first).setOnClickListener {
//            findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)
            testDemo()
        }
        view.findViewById<Button>(R.id.button_loop).setOnClickListener {
            // 测试循环
            testLoop()
        }
        view.findViewById<Button>(R.id.button_class).setOnClickListener {
            // 使用匿名内部类
            object : View.OnClickListener {
                override fun onClick(v: View?) {
                    // 测试类
                    testClass()
                }
            }
        }
    }

18 Object对象

18.1 object对象声明

object声明的对象相当于单例。

    /**
     * 直接声明对象
     */
    object XBus {

        /**
         * 颜色
         */
        var color: String = "绿色"

        /**
         * 座位
         */
        var seat: Int = 30
    }
        println("===测试object对象===")
        // object声明的对象相当于一个单例
        println("XBus 颜色:${XBus.color} 座位: ${XBus.seat} 个")
        // 指向同一个单例对象结果相等
        var obj1 = XBus
        obj1.color = "红色"
        var obj2 = XBus
        println("${obj1 == obj2}")
        // XBus 颜色:红色 座位: 30 个
        println("XBus 颜色:${obj2.color} 座位: ${obj2.seat} 个")

18.2 object函数返回对象

    // 私有函数,所以其返回类型是匿名对象类型
    private fun foo() = object {
        val x: String = "x"
    }

    // 公有函数,所以其返回类型是 Any
    fun publicFoo() = object {
        val x: String = "x"
    }

不能访问到publicFoo().x

19 类型

19.1 空安全

kotlin在定义参数和方法的输入参数时,如果是可以为空的参数,需要显式声明,在参数后面增加?

代表是它的值是可空的, 这样能够减少很多空判断,还能有效避免空指针。

        // 声明变量name是可以为空的变量
        var name: String? = null
        // 判断参数name是否为空,不为空则打印name的长度,为空则输出0
        println(name?.length ?: 0)

19.2 Elvis操作符

Elvis操作符使用?:表示。如果操作符满足,则使用前面的表达式,否则使用:后面的表达式。类似Java的三目操作符。

        // 判断参数name是否为空,不为空则打印name的长度,为空则输出0
        println(name?.length ?: 0)

name不为空,则打印name.length。如果name.length则打印,否则打印“0”

19.3 非空断言

断言表达式不为空,为空则会抛出KotlinNullPointerException

        // 非空断言(str为空则抛出空指针)
        println(name!!.length)

19.4 对象类型判断

使用is 判断对象类型,对应Java的instanceOf

        // 类型转换
        var obj: Any? = "abc"
        if (obj is String) {
            // 会智能转化为对应类型的实例
            println("obj is String length: " + obj.length)
        }

在if (obj is String) 中,obj.length,此时obj已经判断了是String类型,在代码块中不需要进行强制转换,会智能转换为String。这个与Java的使用有点差异。

kotlin使用 as 进行类型强制转换

        // 强制转换
        println("===测试强制转换===")
        // 如果转换成功则转化为String,转换失败则为null
        val str = obj as? String
        // str为非空字符串则打印str长度,否则打印null
        println(str?.length)

因为obj是String,因此强制转换成功,输出str的长度。

强制转换失败,返回的结果时null。

        // 如果转换成功则转化为String,转换失败则为null
        val str = obj as? Int
        // str为非空字符串则打印str长度,否则打印null
        println(str?.toChar())

此时obj类型是String, 强制转换为Int,转换失败,结果为null.

19.5 数组类型

可以通过arrayOf构建数组。

        println("===测试arrayOf数组===")
        var array2 = arrayOf("1", 2, 5)
        for (it in array2) {
            println("$it")
        }

arrayOf中的元素类型可以不相同。

如果构建同一类型元素的数组,可以使用intArrayOf、booleanArrayOf\byteArrayOf。

        // 测试数组类型
        println("===测试intArrayOf数组===")
        var array1 = intArrayOf(1, 2, 5)
        for (it in array1) {
            println("$it")
        }

 

20 泛型

泛型与java类型。用<T>,<E>等表示泛型

    /**
     * 泛型类
     */
    class TestGen<E> {

        /**
         * 对应元素
         */
        var elment: E? = null

        /**
         * 定义泛型方法,输入参数e,输出参数为泛型E类型
         */
        fun <E> add(e: E) {
        }
    }

可以为泛型类或者泛型方法指定限定类,这叫做泛型上限。

    /**
     * 限定参数只能接收 Number 的子类
     */
    fun <E : Number> add(e: E) {}

使用此方法时,输入的参数类型,必须是Number的子类。

泛型通配符 Java 中使用?代表通配符,? extends 类型表示通配符上限,? super 类型表示通配 符下限

21 集合

kotlin集合分为可变集合和只读集合。可变集合采用Mutable定义

可变集合是指集合声明和初始化以后,可以改变集合中元素的值。

        // 测试只读列表
        var readList = listOf("aaa", "bbb", "cccc")
        // 只读集合不允许改变元素的值,编辑器报错
        readList[0] = "1111"

可变集合允许改变元素的值

        // 测试可变集合
        var writeList = mutableListOf(1, 2, 3, 4, 5, 6)
        println("${writeList[0]}")
        writeList[0] = 125
        println("改变后的值${writeList[0]}")

22 序列

序列又被称之为惰性集合,Sequences 序列接口强大在于其操作的实现方式。序列中的
元素求值都是惰性的,所以可以更加高效使用序列来对数据集中的元素进行链式操作(映射、
过滤、变换等),而不需要像普通集合那样,每进行一次数据操作,都必须要开辟新的内存来
存储中间结果,而实际上绝大多数的数据集合操作的需求关注点在于最后的结果而不是中间
的过程.
        // 测试可变集合
        var writeList = mutableListOf(1, 2, 3, 4, 5, 6)
        println("${writeList[0]}")
//        writeList[0] = 125
        println("改变后的值${writeList[0]}")
        // 测试序列
        val result = writeList.filter {
            println("filter $it")
            it > 2
        }.map {
            // 进行变换,原来的值进行映射变化后,返回新的值
            println("map $it")
            it * 2
        }.toList()
        // 打印变换后的结果
        println("===测试序列结果===")
        for (it in result) {
            println("$it")
        }

序列的操作分为两类,中间操作和末端操作,中间操作就是 filter,map 等这些转化,末端操 作就是调用 toList 将序列转化为集合.

序列和集合的使用总结:

什么时候使用序列?
(1) 数据量足够大,使用序列
(2) 对数据集进行频繁的操作,类似于多个操作符链式调用,适用序列
什么时候使用集合?
(1) 数据量比较小
(2) 通过索引访问元素,List 通过索引直接定位到元素,序列需要从前向后遍历
 
 
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值