注:编码工具为IntelliJ
目录
MutableList的mutator函数和removeIf
List
创建
List分为可变和不可变两种,之间可以相互转换。
fun main() {
val intList = listOf(1, 2, 3) // 创建可变List
val intMutableList = mutableListOf(1, 2, 3)// 创建不可变List
println(intList)
println(intMutableList)
println(intList.toMutableList())// 不可变List转换为可变List
println(intMutableList.toList())// 可变List转换为不可变List
}
输出:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
元素获取
可变和不可变List获取元素方式相同:get、[]、getOrElse、getOrNull。
get和[]本质相同,下标越界会抛异常。
getOrElse,如果下标没越界,返回对应下标的元素,否则,返回指定值。
getOrNull,如果下标没越界,返回对应下边的元素,否则,返回null。
fun main() {
val list = mutableListOf(111, 2, 333, 4)
println(list.get(0))
// println(list.get(4))// java.lang.IndexOutOfBoundsException
println(list[3])// [] 实际和get本质相同
// println(list[30])// java.lang.IndexOutOfBoundsException
println(list.getOrElse(3) { 9 })
println(list.getOrElse(33) { 9 })
println(list.getOrNull(2))
println(list.getOrNull(100))
}
输出:
111
4
4
9
333
null
可变和不可变List的区别
可以对可变List进行元素的增删改操作。
fun main() {
val list = mutableListOf("I", "Miss", "You")
println(list)
list.add("Hope")
println(list)
list.set(1, "Love")
println(list)
list.remove("Hope")
println(list)
}
输出:
[I, Miss, You]
[I, Miss, You, Hope]
[I, Love, You, Hope]
[I, Love, You]
MutableList的mutator函数和removeIf
mutator函数:+= 添加元素、-= 移除元素
removeIf函数:删除满足条件的元素
fun main() {
val list = mutableListOf("A", "D", "Min", "i", "S")
list += "T" // += 等于 add
println(list)
list -= "Min"// -= 等于 remove
println(list)
list.removeIf { it >= "i" }
println(list)
}
输出:
[A, D, Min, i, S, T]
[A, D, i, S, T]
[A, D, S, T]
遍历
方式一:
fun main() {
val list = listOf(1, 3, 4)
for(i in list)
{
print("$i ")
}
}
输出:
1 3 4
方式二:
fun main() {
val list = listOf(1, 3, 4)
list.forEach {
print("$it ")
}
}
输出:
1 3 4
方式三:
fun main() {
val list = listOf(1, 3, 4)
list.forEachIndexed { index, i ->
print("$index-$i ")
}
}
输出:
0-1 1-3 2-4
解构
fun main(){
val list = mutableListOf("A", "B", "C", "Z")
println(list)
var (a, b, c, d) = list
println("a:$a, b:$b, c:$c, d:$d")
val (_, f, g, h) = list// _符号可以屏蔽不想解构的元素
println("f:$f, g:$g, h:$h)
}
输出:
[A, B, C, Z]
a:A, b:B, c:C, d:Z
f:B, g:C, h:Z
Set
特点:元素不可重复,可用于去重。
Set分为可变和不可变两种,之间可以相互转换。
可以和List之间相互转换。
fun main() {
val intSet = setOf(1, 2, 3, 4, 4)// 创建不可变Set
println(intSet)// 只有一个4
val intMutableSet = mutableSetOf(1, 2, 1, 3, 4)// 创建可变Set
println(intMutableSet)// 只有一个1
println("-----------Set之间转换------------")
println(intSet.toMutableSet())// 不可变Set转换为可变Set
println(intMutableSet.toSet())// 可变Set转换为不可变Set
println("-----------Set To List------------")
println(intSet.toList())// 不可变Set转换为不可变List
println(intSet.toMutableList())// 不可变Set转换为可变List
println(intMutableSet.toList())// 可变Set转换为不可变List
println(intMutableSet.toMutableList())// 可变Set转换为可变List
println("-----------List To Set------------")
val charList = listOf('a', 'b', 'c', 'd')
val charMutableList = mutableListOf('d', 'c', 'b', 'a')
println(charList.toSet())// 不可变List转换为不可变Set
println(charList.toMutableSet())// 不可变List转换为可变Set
println(charMutableList.toSet())// 可变List转换为不可变Set
println(charMutableList.toMutableSet())// 可变List转换为可变Set
}
输出:
[1, 2, 3, 4]
[1, 2, 3, 4]
-----------Set之间转换------------
[1, 2, 3, 4]
[1, 2, 3, 4]
-----------Set To List------------
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
-----------List To Set------------
[a, b, c, d]
[a, b, c, d]
[d, c, b, a]
[d, c, b, a]
元素获取
可变和不可变Set获取元素方式相同:elementAt, elementAtOrElse、elementAtOrNull。
elementAt下标越界会抛异常。
elementAtOrElse,如果下标没越界,返回对应下标的元素,否则,返回指定值。
elementAtOrNull,如果下标没越界,返回对应下边的元素,否则,返回null。
fun main() {
val set = setOf(1, 3, 2, 5)
// set.elementAt(5) // java.lang.IndexOutOfBoundsException
println(set.elementAt(0))
println(set.elementAtOrElse(3) { it })
println(set.elementAtOrElse(5) { it })
println(set.elementAtOrNull(1))
println(set.elementAtOrNull(100))
}
输出:
1
5
5
3
null
MutableSet的mutator函数和removeIf
mutator函数:+= 添加元素、-= 移除元素
removeIf函数:删除满足条件的元素
fun main() {
val set = mutableSetOf("A", "T", "Z")
println(set)
set += "O"
set += "ABC"
println(set)
set -= "\""
set -= "ABC"
println(set)
set.removeIf{
it == "O"
}
println(set)
}
输出:
[A, T, Z]
[A, T, Z, O, ABC]
[A, T, Z, O]
[A, T, Z]
List转Set去重
fun main() {
val list = listOf(1, 3, 5, 3, 3, 2, 5)
println(list)
println(list.toSet())
println(list.toSet().toList())
}
输出:
[1, 3, 5, 3, 3, 2, 5]
[1, 3, 5, 2]
[1, 3, 5, 2]
Map
创建
Map分为可变和不可变两种,之间可以相互转换。
fun main() {
val map = mapOf(1 to 2, 3 to 4, 5 to 6)
val mutableMap = mutableMapOf(Pair('a', 1), Pair('b', 2), 'c' to 3)
println(map.toMutableMap())// 不可变Map转换为可变Map
println(mutableMap.toMap())// 可变Map转换为不可变Map
}
输出:
{1=2, 3=4, 5=6}
{a=1, b=2, c=3}
元素获取
可变和不可变Map获取元素方式相同:[]、get、getValue、getOrDefault、getOrElse。
[]和get本质相同,key不存在返回null。
getValue,如果key存在,返回对应value,否则,抛出异常。
getOrDefault,如果key存在,返回对应value,否则,返回default值。
getOrElse,如果下标没越界,返回对应value,否则,返回指定值。
fun main() {
val map = mutableMapOf(1 to 'a', 2 to 'c', 3 to 'e')
println(map[1])
println(map[4])// key不存在返回null
println(map.get(2))
println(map.get(100))// key不存在返回null
println(map.getValue(3))
// println(map.getValue(1000))// java.util.NoSuchElementException
println(map.getOrDefault(1, 'A'))
println(map.getOrDefault(15, 'A'))
println(map.getOrElse(1) { 'E' })
println(map.getOrElse(99) { 'V' })
}
输出:
a
null
c
null
e
a
A
a
V
遍历
方式一
fun main() {
val map = mapOf('A' to 'Z', 'B' to 'Y')
for(i in map){
println("key = ${i.key}, value = ${i.value}")
}
}
输出:
key = A, value = Z
key = B, value = Y
方式二:
fun main() {
val map = mapOf('A' to 'Z', 'B' to 'Y')
for((k, v) in map){
println("$k:$v")
}
}
输出:
A:Z
B:Y
方式三:
fun main() {
val map = mapOf('A' to 'Z', 'B' to 'Y')
map.forEach{
println("${it.key} to ${it.value}")
}
}
输出:
A to Z
B to Y
方式四:
fun main() {
val map = mapOf('A' to 'Z', 'B' to 'Y')
map.forEach{(k, v) -> println("k = $k, v = $v")}
}
输出:
k = A, v = Z
k = B, v = Y
可变Map的mutator函数和增删改操作
fun main() {
val map = mutableMapOf(3 to 5, 7 to 1)
println(map)
map += 3 to 9
println(map)
map += 10 to 2
println(map)
map += 4 to 100
println(map)
map -= 1
println(map)
map -= 7
println(map)
map[33] = 333
println(map)
map.put(3, 13)
println(map)
println(map.getOrPut(3){10000})
println(map.getOrPut(100){10000})
}
输出:
{3=5, 7=1}
{3=9, 7=1}
{3=9, 7=1, 10=2}
{3=9, 7=1, 10=2, 4=100}
{3=9, 7=1, 10=2, 4=100}
{3=9, 10=2, 4=100}
{3=9, 10=2, 4=100, 33=333}
{3=13, 10=2, 4=100, 33=333}
13
10000
数组
创建
fun main() {
val arrayOf = arrayOf('a', 'A', 'C')
println(arrayOf.contentDeepToString())
val intArr = intArrayOf(1, 2, 3)
println(intArr.contentToString())
/**
* 类似的还有
* shortArrayOf()
* byteArrayOf()
* charArrayOf()
* longArrayOf()
* booleanArrayOf()
* floatArrayOf()
* doubleArrayOf()
*/
}
输出:
[a, A, C]
[1, 2, 3]
元素获取
[]、get、elementAt、elementAtOrElse、elementAtOrNull。
[]、get、elementAt本质相同,下标越界会抛异常。
elementAtOrElse,如果下标没越界,返回对应下标的元素,否则,返回指定值。
elementAtOrNull,如果下标没越界,返回对应下边的元素,否则,返回null。
fun main() {
val arr = arrayOf(1, 2, 3)
println(arr.contentToString())
println(arr[2])
// println(arr[3])// java.lang.ArrayIndexOutOfBoundsException
println(arr.get(0))
arr.set(2,20)
println(arr.contentToString())
println((arr + 4).contentToString())
// println((arr - 3).contentToString()) // 没有-符号重载
println(arr.elementAt(0))
println(arr.elementAtOrElse(5) { it })
println(arr.elementAtOrNull(5))
}
输出:
[1, 2, 3]
3
1
[1, 2, 20]
[1, 2, 20, 4]
1
5
null
与List、Set之间的转换
fun main() {
val intArr = intArrayOf(1, 2, 3, 4)
println(intArr.toSet())// Array转换为Set
println(intArr.toList())// Array转换为List
val set = setOf("I", "Love", "MySelf")
println(set.toTypedArray().contentToString())// Set转换为Array
val list = listOf("I", "Trust", "MySelf")
println(list.toTypedArray().contentToString())// list转换为Array
}
输出:
[1, 2, 3, 4]
[1, 2, 3, 4]
[I, Love, MySelf]
[I, Trust, MySelf]
对象数组
fun main() {
val peopleArray = arrayOf(Person("ZhangSan"), Person("LiSi"))
for (person in peopleArray)
{
println(person.name)
}
}
输出:
ZhangSan
LiSi
类
极简类定义
只有类名,如下所示:
class MinimalistClass
有成员变量的类的定义简单示例
class Demo{
var name: String = ""
val grade: String = "3"
}
反编译后的Java代码:
public final class Demo {
@NotNull
private String name = "";
@NotNull
private final String grade = "3";
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}
@NotNull
public final String getGrade() {
return this.grade;
}
}
如上所示,Kotlin的类成员变量反编译成Java代码后会变为private的,其中var修饰的变量会提供getter、setter,而val修饰的变量则只会提供getter。
类成员的get、set属性和field
Kotlin的类成员默认都有一个field变量,var修饰的变量默认会提供set()和get()方法,val修饰的变量默认会提供get()方法。
set()方法默认会将入参赋值给field,get()方法默认会返回field。
可以自定义var修饰的变量的set()和get()方法,val修饰的变量的get()方法。
class Field{
var name: String = "Knuth"// var 修饰的变量既有set() 又有get()
set(value){
field = value
}
get() = "[$field]"
val hobby = "travel" //val 修饰的变量只有get()
get() = "hobby:$field"
val age : Int // = 1 不能赋值,因为在get()方法中给定了值,使其没有后端field
get() {
println("before get age")
return 99
}
}
fun main() {
val field = Field()
println("name = ${field.name}, hobby = ${field.hobby}, age = ${field.age}")
}
输出:
before get age
name = [Knuth], hobby = hobby:travel, age = 99
构造函数
主构造函数
在类型后面加一对圆括号,如果没有参数,圆括号可以省略,否则,在圆括号里进行参数声明。
有参数:
没有var/val修饰,需要在类内部定义变量接收主构造函数中传入的参数;
有var/val修饰,主构造函数的参数直接作为类的成员变量使用。
没有var/val修饰示例:
class MainCon(name: String, age: Int){
var name = name
var age = age
}
反编译后的Java代码:
public final class MainCon {
@NotNull
private String name;
private int age;
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}
public final int getAge() {
return this.age;
}
public final void setAge(int var1) {
this.age = var1;
}
public MainCon(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
}
有var/val修饰示例:
class MainCon2(var name: String, val age: Int)
反编译后的Java代码:
public final class MainCon2 {
@NotNull
private String name;
private final int age;
@NotNull
public final String getName() {
return this.name;
}
public final void setName(@NotNull String var1) {
Intrinsics.checkNotNullParameter(var1, "<set-?>");
this.name = var1;
}
public final int getAge() {
return this.age;
}
public MainCon2(@NotNull String name, int age) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
this.age = age;
}
}
次构造函数
必须调用主构造函数。
有参数时不能用var/val修饰。
有参数且主构造函数没有参数时,只能定义成员变量接收。
class SubCon(){
var name: String = ""
constructor(name: String) : this(){
this.name = name
}
}
有参数且主构造函数有参数且用var/val修饰时,可以将参数传给主构造函数然后直接作为属性使用。
class SubCon2(var name: String, var age:Int){
constructor(name: String): this(name, 99)
}
构造函数默认参数
class Content(var name: String, var age: Int = 99){
constructor(name: String = "Default"):this(name, 88)
}
fun main() {
val content = Content("happy")
println("name = ${content.name}, age = ${content.age}")
val content2 = Content("Seo")
println("name = ${content2.name}, age = ${content2.age}")
val content3 = Content("author", 100)
println("name = ${content3.name}, age = ${content3.age}")
}
输出:
name = happy, age = 88
name = Seo, age = 88
name = author, age = 100
init初始化块
主构造函数调用时被调用,可用于初始化定义在类内部的成员变量。
class InitTest(name: String, age: Int){
var name: String
var age: Int
init{
this.name = name
this.age = age
}
fun show(){
println("name:$name, age:$age")
}
}
fun main() {
InitTest("C.C", 999999).show()
}
输出:
name:C.C, age:999999
构造函数初始化顺序
// 第二步
class Student(var name: String, age: Int){
// gender赋值、init块和bornPlace赋值按照代码先后顺序执行
// 第三步
var gender = "M"
var age: Int
init{
// 第四步
this.age = age
}
// 第五步
val bornPlace = "BeiJing"
// 第一步
constructor(name: String):this(name,18)
}
fun main() {
Student("小明")
}
延迟初始化:lateinit
class Animal{
lateinit var name: String
fun show(){
if(::name.isInitialized)
{
println("name is $name")
}else{
println("name has not been initialized")
}
}
fun init(){
name = "AFu"
show()
}
}
fun main() {
val animal = Animal()
animal.show()
animal.init()
}
输出:
name has not been initialized
name is AFu
by lazy:懒加载
在用到的时候才加载
class LazyDemo{
// 在类实例定义时会执行赋值操作,所以会调用init,所以info会被立即赋值
var info = init()
// 在类实例定义时不会执行赋值操作,在info第一次被用到的时候才会被赋值
val into2 by lazy {
println("do once")
"this is a lazy load value"
}
fun init(): String{
println("do something...")
return "HH"
}
}
fun main() {
val ld = LazyDemo()// 会执行init方法给info赋值
println("---------------------------")
println("info is ${ld.info}")
println("info2 is ${ld.into2}")
println("info2 is ${ld.into2}")
}
输出:
do something...
---------------------------
info is HH
do once
info2 is this is a lazy load value
info2 is this is a lazy load value
一些初始化错误:
理解了构造函数初始化顺序就能理解错误原因。
一:编译不过
class InitError1{
init{
number = number.times(9)
}
var number = 9
}
二:
class InitError2{
var info : String
init{
showInfo()
info = "Init"
}
fun showInfo(){
println("${info[0]}")
}
}
fun main() {
InitError2()// java.lang.NullPointerException
}
输出:
Exception in thread "main" java.lang.NullPointerException
at step_four.InitError2.showInfo(InitError2.kt:11)
at step_four.InitError2.<init>(InitError2.kt:6)
at step_four.InitError2Kt.main(InitError2.kt:16)
at step_four.InitError2Kt.main(InitError2.kt)
三:
class InitError3(i: String){
val c = get()
val info = i
fun get() = info
}
fun main(){
println(InitError3("MoonLight").c.length)// java.lang.NullPointerException
}
输出:
Exception in thread "main" java.lang.NullPointerException
at step.four.InitError3Kt.main(InitError3.kt:10)
at step.four.InitError3Kt.main(InitError3.kt)