• [技术干货] 【Kotlin】委托模式
    1 委托模式简介​ 委托模式的类图结构如下。​ 对应的 Kotlin 代码如下。fun main() { var baseImpl = BaseImpl() var baseWrapper = BaseWrapper(baseImpl) baseWrapper.myFun1() // 打印: BaseImpl, myFun1 baseWrapper.myFun2() // 打印: BaseImpl, myFun2 } interface Base { fun myFun1() fun myFun2() } class BaseWrapper(var baseImpl: Base): Base { override fun myFun1() { baseImpl.myFun1() } override fun myFun2() { baseImpl.myFun2() } } class BaseImpl: Base { override fun myFun1() { println("BaseImpl, myFun1") } override fun myFun2() { println("BaseImpl, myFun2") } }2 类委托​ Kotlin 可以简化 BaseWrapper,简化后的代码如下。fun main() { var baseImpl = BaseImpl() var baseWrapper = BaseWrapper(baseImpl) baseWrapper.myFun1() // 打印: BaseImpl, myFun1 baseWrapper.myFun2() // 打印: BaseImpl, myFun2 } interface Base { fun myFun1() fun myFun2() } class BaseWrapper(var baseImpl: Base): Base by baseImpl class BaseImpl: Base { override fun myFun1() { println("BaseImpl, myFun1") } override fun myFun2() { println("BaseImpl, myFun2") } }3 属性委托3.1 by Timport kotlin.reflect.KProperty fun main() { var str: String by StringDelegate() str = "abc" println(str) } class StringDelegate { var value: String? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): String { println("getValue, thisRef=$thisRef, name=${property.name}, value=$value") return value ?: throw IllegalStateException("Property not initialized") } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("setValue, thisRef=$thisRef, name=${property.name}, value=$value") this.value = value } }​ 打印日志如下。setValue, thisRef=null, name=str, value=ABC getValue, thisRef=null, name=str, value=ABC ABC3.2 by lazyfun main() { // lazy为生成的委托对象, 获取属性时会执行lazy里面的操作, 只支持val变量 val str: String by lazy { "666" } println(str) // 打印: 666 }3.3 by Delegates.observablefun main() { var str: String by Delegates.observable("666") { prop, old, new -> println("prop=$prop, old=$old, new=$new") } println(str) // 666 // prop=property str (Kotlin reflection is not available), old=666, new=888 str = "888" }3.4 by ::Tfun main() { var example = Example("ABC") example.str2 = "DEF" // str1=DEF, str2=DEF println("str1=${example.str1}, str2=${example.str2}") } class Example(var str1: String) { var str2: String by ::str1 }​ 说明:属性被委托后,str1 和 str2 同时修改。3.5 by mapfun main() { var map: MutableMap<String, Any> = mutableMapOf( "name" to "Tom", "age" to 23, "id" to 1001 ) var user = User(map) println(user) // (Tom, 23, 1001) } class User(map: MutableMap<String, Any>) { var name: String by map var age: Int by map var id: Int by map override fun toString(): String = "($name, $age, $id)" }​ 声明:本文转自【Kotlin】委托模式。
  • [技术干货] 【Kotlin】匿名类和伴生类
    1 匿名类​ 1)无继承fun main() { var obj = object { var name: String = "zhang" override fun toString(): String { return name } } println(obj) // zhang }​ 2)有继承fun main() { var obj = object: People { var name: String = "zhang" override fun play() { println("play, $name") } } obj.play() // play, zhang } interface People { fun play() }2 单例2.1 案例一​ 1)object 单例fun main() { var singleton = Singleton println(singleton) } object Singleton { var name = "zhang" override fun toString(): String { return return name } }​ 2)对应的 java 类​ Singleton.javapublic final class Singleton { private static String name; public static final Singleton INSTANCE; static { INSTANCE = new Singleton(); name = "zhang"; } private Singleton() { } public final String getName() { return name; } public final void setName(String var1) { name = var1; } public String toString() { return name; } }​ java 中调用如下。Singleton singleton = Singleton.INSTANCE; System.out.println(singleton);2.2 案例二​ 1)object 单例fun main() { var stu = Student.Tools.create("zhang") println(stu) // zhang println(Student.Tools.age) // 15 } class Student(var name: String) { object Tools { var age: Int = 15 fun create(name: String): Student { return Student(name) } } override fun toString(): String { return name } }​ 2)对应的 java 类​ Student.javapublic final class Student { private String name; public Student(String name) { this.name = name; } public final String getName() { return this.name; } public final void setName(String var1) { this.name = var1; } public String toString() { return this.name; } public static final class Tools { private static int age; public static final Tools INSTANCE; static { INSTANCE = new Tools(); age = 15; } private Tools() { } public final Student create(String name) { return new Student(name); } public final int getAge() { return age; } public final void setAge(int var1) { age = var1; } } }​ java 中调用如下。Student stu = Student.Tools.INSTANCE.create("zhang"); System.out.println(stu); System.out.println(Student.Tools.INSTANCE.getAge());3 伴生类3.1 伴生类应用​ 1)应用fun main() { var stu = Student.create("zhang") println(stu) // zhang println(Student.age) // 15 } class Student(var name: String) { companion object Tools { var age: Int = 15 fun create(name: String): Student { return Student(name) } } override fun toString(): String { return name } }​ 2)反编译后 java 类​ Student.javapublic final class Student { private String name; private static int age = 15; public static final Tools Tools = new Tools((); public Student(String name) { this.name = name; } public final String getName() { return this.name; } public final void setName(String var1) { this.name = var1; } public String toString() { return this.name; } public static final class Tools { private Tools() { } public final Student create(String name) { return new Student(name); } public final int getAge() { return Student.age; } public final void setAge(int var1) { Student.age = var1; } } }​ java 中调用如下。Student stu = Student.Tools.create("zhang"); System.out.println(stu); System.out.println(Student.Tools.getAge());3.2 @JvmStatic 应用​ 为方便 Java 中也可以直接调用 Student.create(),可以给伴生类中的函数添加 @JvmStatic 注解。​ 1)应用class Student(var name: String) { companion object Tools { var age: Int = 15 @JvmStatic fun create(name: String): Student { return Student(name) } } override fun toString(): String { return name } }​ java 中调用如下。Student stu = Student.create("zhang"); System.out.println(stu); System.out.println(Student.Tools.getAge());​ 2)反编译后 java 类public final class Student { private String name; private static int age = 15; public static final Tools Tools = new Tools(); public Student(String name) { this.name = name; } public static final Student create(String name) { return Tools.create(name); } public final String getName() { return this.name; } public final void setName(String var1) { this.name = var1; } public String toString() { return this.name; } public static final class Tools { private Tools() { } public final Student create(String name) { return new Student(name); } public final int getAge() { return Student.age; } public final void setAge(int var1) { Student.age = var1; } } }​ 说明:对比有无 @JvmStatic 注解反编译后的代码,发现有 @JvmStatic 注解时,反编译的代码里 Student 类中多了静态的 create 方法,因此在 Java 中可以直接调用 Student.create()。​ 声明:本文转自【Kotlin】匿名类和伴生类。
  • [技术干货] 【Kotlin】Sequence简介
    1 前言​ 序列(Sequence)是 Kotlin 中为方便操作集合及其元素而定制的接口,是一个延迟获取数据的集合,只有需要元素时才会生产元素。在处理大量数据时,序列可以显著地提升性能。​ Sequence 类似 Java 中的 Stream,详见 → Stream 总结。Sequence 有中间操作和终端操作,如下。中间操作:每次操作返回一个新的 Sequence 对象(主要操作有:filter、distinct、drop、take、sorted、sortedDescending、map、mapIndexed、minus 等)。终端操作:每次操作返回一个值或集合,每个序列只能进行一次终端操作(主要操作有:forEach、joinToString、min、max、count、sum、average、any、first、last、reduce 等)。2 Sequence 的创建2.1 sequenceOfvar sequence = sequenceOf(1, 2, 3)2.2 asSequence​ 1)IntRangevar intRange = 1..10 var sequence = intRange.asSequence()​ 2)Arrayvar array = arrayOf(1, 2, 3) var sequence = array.asSequence()​ 3)Listvar list = listOf("AA", "BBB", "CC") var sequence = list.asSequence()​ 4)Setvar set = setOf("AA", "BBB", "CC") var sequence = set.asSequence()2.3 BufferedReaderval reader = BufferedReader(FileReader("G:\\stream.txt")) val sequence = reader.lineSequence()2.4 generateSequencevar sequence = generateSequence(arrayOf(1, 1)) { arr -> arrayOf(arr[1], arr[0] + arr[1]) } .take(10) .map { arr -> arr[0] } // 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 println(sequence.joinToString())3 Sequence 的中间操作3.1 主要接口// 过滤 public fun <T> Sequence<T>.filter(predicate: (T) -> Boolean): Sequence<T> // 去重 public fun <T> Sequence<T>.distinct(): Sequence<T> // 丢弃前 n 个元素 public fun <T> Sequence<T>.drop(n: Int): Sequence<T> // 截取前 n 个元素 public fun <T> Sequence<T>.take(n: Int): Sequence<T> // 排序(升序) public fun <T : Comparable<T>> Sequence<T>.sorted(): Sequence<T> // 排序(降序) public fun <T : Comparable<T>> Sequence<T>.sortedDescending(): Sequence<T> // 映射(T -> R) public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> // 映射(index, T -> R) public fun <T, R> Sequence<T>.mapIndexed(transform: (index: Int, T) -> R): Sequence<R> // 删除序列中第一个 element public operator fun <T> Sequence<T>.minus(element: T): Sequence<T>3.2 案例fun main() { var sequence = sequenceOf(4, 9, 1, 8, 5, 5, 7, 3, 6, 2) sequence.filter { it in 3..7 } // 4 5 5 7 3 6 .distinct() // 4 5 7 3 6 .drop(1) // 5 7 3 6 .take(3) // 5 7 3 .sorted() // 3 5 7 .map { it * it } // 9 25 49 .forEach(::println) }4 Sequence 的终端操作4.1 主要接口​ 1)统计函数// 最小值 public fun <T : Comparable<T>> Sequence<T>.min(): T? // 最大值 public fun <T : Comparable<T>> Sequence<T>.max(): T? // 元素个数 public fun <T> Sequence<T>.count(): Int // 求和 public fun Sequence<Int>.sum(): Int // 求平均值 public fun Sequence<Int>.average(): Double // 序列中是否有元素 public fun <T> Sequence<T>.any(): Boolean // 获取第一个元素 public fun <T> Sequence<T>.first(): T // 获取最后一个元素 public fun <T> Sequence<T>.last(): T​ 2)遍历元素// 遍历元素 public inline fun <T> Sequence<T>.forEach(action: (T) -> Unit): Unit​ 3)拼接元素// 转换为字符串 public fun <T> Sequence<T>.joinToString(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "", limit: Int = -1, truncated: CharSequence = "...", transform: ((T) -> CharSequence)? = null): String​ 4)规约运算// 规约运算,定义运算 o, result = ((((e1 o e2)) o e3) o e4) o ... public inline fun <S, T : S> Sequence<T>.reduce(operation: (acc: S, T) -> S): S​ 5)集合转换public fun <T> Sequence<T>.toList(): List<T> public fun <T> Sequence<T>.toMutableList(): MutableList<T> public fun <T> Sequence<T>.toSet(): Set<T> public fun <T> Sequence<T>.toMutableSet(): MutableSet<T> public fun <T> Sequence<T>.toHashSet(): HashSet<T> public fun <T : Comparable<T>> Sequence<T>.toSortedSet(): java.util.SortedSet<T>4.2 案例​ 1)统计函数fun main() { var sequence = sequenceOf(1, 3, 5) var min = sequence.min() // 1 var max = sequence.max() // 5 var count = sequence.count() // 3 var sum = sequence.sum() // 9 var avg = sequence.average() // 3 var hasElement = sequence.any() // true var first = sequence.first() // 1 var last = sequence.last() // 5 }​ 2)遍历元素fun main() { var sequence = sequenceOf(1, 3, 5) sequence.forEach(::println) // 1、3、5 }​ 3)拼接元素fun main() { var sequence = sequenceOf(1, 3, 5) var str = sequence.joinToString(",", "[", "]") }​ 4)规约运算fun main() { var sequence = sequenceOf(1, 3, 5) var sum = sequence.reduce(Integer::sum) // 9 // 1*1-3*3=-8, (-8)*(-8)-5*5=39 var res = sequence.reduce { e1, e2 -> e1 * e1 - e2 * e2 } // 39 }​ 5)集合转换fun main() { val sequence = sequenceOf(1, 2, 3) var list1 = sequence.toCollection(mutableListOf()) var list2 = sequence.toList() var mutableList = sequence.toMutableList() var set1 = sequence.toCollection(mutableSetOf()) var set2 = sequence.toSet() var mutableSet = sequence.toMutableSet() var hashSet = sequence.toHashSet() var sortedSet = sequence.toSortedSet() }​ 声明:本文转自【Kotlin】Sequence简介。
  • [技术干货] 【Kotlin】Map简介
    3 Map3.1 创建 Map3.1.1 Pair​ 1)Pair 构造函数public data class Pair<out A, out B>( public val first: A, public val second: B ) : Serializable​ 2)to 函数public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)​ 3)应用var pair: Pair<Int, String> = 1001 to "Tom"3.1.2 emptyMapvar map = emptyMap<Int, String>()3.1.3 Map 构造函数var map1 = HashMap<Int, String>() var map2 = Hashtable<Int, String>() var map3 = LinkedHashMap<Int, String>() var map4 = ConcurrentHashMap<Int, String>() var map5 = TreeMap<Int, String>()3.1.4 mapOfvar map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" )3.2 增删改查3.2.1 增加元素​ 1)putfun main() { var map: MutableMap<Int, String> = mutableMapOf() map.put(1001, "Tom") }​ 2)map[key] = valuefun main() { var map: MutableMap<Int, String> = mutableMapOf() map[1002] = "Mary" }​ 2)+fun main() { var map: MutableMap<Int, String> = mutableMapOf() map += 1001 to "John" map += arrayOf(1002 to "Zhang") map += listOf(1003 to "Wang") map += setOf(1004 to "Li") map += mapOf(1005 to "Xie") }​ 4)putAllfun main() { var map: MutableMap<Int, String> = mutableMapOf() var list1 = listOf(1, 2, 3) var list2 = listOf("zhang", "li", "wang") map.putAll(list1.zip(list2)) }3.2.2 删除元素fun main() { var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) map.remove(1001) map -= 1002 map -= arrayOf(1003) map -= listOf(1004) map -= setOf(1005) map.clear() }3.2.3 修改元素var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) map[1001] = "John"3.2.4 访问元素​ 1)访问元素var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) println(map[1001]) // Tom​ 2)遍历元素fun main() { var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) map.forEach { key, value -> println("[$key, $value]") // [1001, Tom], [1002, Mary] } for ((key, value) in map) { println("[$key, $value]") // [1001, Tom], [1002, Mary] } }3.3 keys 和 values3.3.1 keys、values、entriesfun main() { var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) println(map.keys) // [1001, 1002] println(map.values) // [Tom, Mary] for (entry in map.entries) { println("[${entry.key}, ${entry.value}]") // [1001, Tom], [1002, Mary] } println(map.containsKey(1001)) // true println(map.containsValue("Tom")) // true }3.3.2 mapKeys、mapValuesfun main() { var map1: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) var map2 = map1.mapKeys { it.key - 1000 } // {1=Tom, 2=Mary} var map3 = map1.mapValues { it.value + "X" } // {1001=TomX, 1002=MaryX} }3.4 getOrDefault、getOrElse、getOrPutfun main() { var map: MutableMap<Int, String> = mutableMapOf( 1001 to "Tom", 1002 to "Mary" ) // 在没有结果时返回给定的默认值 var name1 = map.getOrDefault(1001, "xxx") // 使用函数式返回默认值 var name2 = map.getOrElse(1001) { "xxx" } // 添加(1003, John), 并返回John var name3 = map.getOrPut(1003) { "John" } } 声明:本文转自【Kotlin】Map简介。
  • [技术干货] 【Kotlin】Set简介
    2 Set2.1 创建 Set2.1.1 emptySetvar set = emptySet<String>()2.1.2 Set 构造函数var set1 = HashSet<Int>() var set2 = LinkedHashSet<String>() var set3 = TreeSet<String>()2.1.3 setOfvar set1: Set<String> = setOf() // 只读Set var set2: MutableSet<String> = mutableSetOf() // LinkedHashSet var set3: HashSet<String> = hashSetOf() // HashSet var set4: LinkedHashSet<String> = linkedSetOf() // LinkedHashSet var set5: TreeSet<String> = sortedSetOf() // TreeSet var set6: Set<String> = setOf("zhang", "li", "wang") var set7: MutableSet<String> = mutableSetOf("zhang", "li", "wang") var set8 = setOfNotNull(true, 5, 3f, "abc", null)2.1.4 根据 Array 创建 Setvar arr = arrayOf(1, 2, 3) var set1 = setOf(arr) var set2 = setOfNotNull(arr)2.2 增删改查2.2.1 增加元素fun main() { var set = mutableSetOf<String>() set.add("abc") set.add("xyz") set += "ABC" set += arrayOf("123") set += listOf("456") set += setOf("789") }2.2.2 删除元素fun main() { var set = mutableListOf("abc", "efg", "xyz") set.remove("abc") set.removeAt(0) set -= "xyz" set -= arrayOf("123") set -= listOf("456") set -= setOf("789") set.clear() }2.2.3 访问元素​ 1)访问元素fun main() { var set = mutableSetOf("zhan", "li", "wang") println(set.elementAt(1)) // 打印: li set.any() // true, 判断List是否为空(容量为0) set.first() // chen, 获取首个元素 set.last() // wang, 获取最后一个元素 set.indexOf("wang") // 2, 查找元素对应的索引 }​ 2)遍历元素fun main() { var set = mutableSetOf("abc", "efg", "xyz") set.forEach(::println) // abc, efg, xyz for ((index, item) in set.withIndex()) { println("[$index, $item]") // [0, abc], [1, efg], [2, xyz] } }2.3 修改元素顺序2.3.1 翻转元素fun main() { var set = mutableSetOf(1, 2, 3, 4, 5) var list = set.reversed() // 翻转Set元素顺序, 并生成新的List }2.3.2 打乱元素顺序fun main() { var set = mutableSetOf(1, 2, 3, 4, 5) var list = set.shuffled() // 打乱Set元素顺序, 并生成新的List }2.3.3 元素排序fun main() { var set = mutableSetOf(3, 1, 5, 2, 4) var list1 = set.sorted() // 从小到大排序, 并生成新的List var list2 = set.sortedDescending() // 从大到小排序, 并生成新的List }2.4 统计函数fun main() { var set = mutableSetOf(1, 2, 3) set.sum() // 6 set.average() // 2.0 set.max() // 3 set.min() // 1 set.count() // 3 }2.5 集合运算fun main() { var set1 = setOf("AAA", "BBB") var set2 = setOf("BBB", "CCC") println(set1 + set2) // [AAA, BBB, BBB, CCC] println(set1 - set2) // [AAA] println(set1 union set2) // [AAA, BBB, CCC] println(set1 intersect set2) // [BBB] println(set1 subtract set2) // [AAA] println(set2 subtract set1) // [CCC] println((set1 - set2) union (set2 - set1)) // [AAA, CCC] } 声明:本文转自【Kotlin】Set简介。
  • [技术干货] 【Kotlin】List简介
    1 List1.1 创建 List1.1.1 emptyListvar list = emptyList<String>() // 创建空List1.1.2 List 构造函数var list1 = List(3) { "abc" } // [abc, abc, abc] var list2 = ArrayList<Int>() var list3 = LinkedList<String>()1.1.3 listOfvar list1: List<String> = listOf() // 只读List var list2: MutableList<String> = mutableListOf() // ArrayList var list3: List<String> = listOf("zhang", "li", "wang") var list4: MutableList<String> = mutableListOf("zhang", "li", "wang") var list5 = listOfNotNull(true, 5, 3f, "abc", null)​ 说明:listof 和 listOfNotNull 生成的列表是只读列表,不能修改。1.1.4 根据 Array 创建 Listvar arr = arrayOf(1, 2, 3) var list1 = listOf(arr) var list2 = listOfNotNull(arr)1.2 增删改查1.2.1 增加元素fun main() { var list = mutableListOf<String>() list.add("abc") list.add("xyz") list.add(1, "ABC") list += "XYZ" list += arrayOf("123") list += listOf("456") list += setOf("789") }1.2.2 删除元素fun main() { var list = mutableListOf("abc", "efg", "xyz") list.remove("abc") list.removeAt(0) list -= "xyz" list -= arrayOf("123") list -= listOf("456") list -= setOf("789") list.clear() }1.2.3 修改元素var list = mutableListOf("abc", "efg", "xyz") list[0] = "ABC"1.2.4 访问元素​ 1)访问元素fun main() { var list = mutableListOf("zhan", "li", "wang") println(list[1]) // 打印: li list[0] = "chen" list.any() // true, 判断List是否为空(容量为0) list.first() // chen, 获取首个元素 list.last() // wang, 获取最后一个元素 list.indexOf("wang") // 2, 查找元素对应的索引 list.binarySearch("wang") // 2, 二分查找元素对应的索引 }​ 2)遍历元素fun main() { var list = mutableListOf("abc", "efg", "xyz") list.forEach(::println) // abc, efg, xyz for ((index, item) in list.withIndex()) { println("[$index, $item]") // [0, abc], [1, efg], [2, xyz] } }1.3 修改元素顺序1.3.1 翻转元素fun main() { var list1 = mutableListOf(1, 2, 3, 4, 5) var list2 = list1.reversed() // 翻转List元素顺序, 并生成新的List list1.reverse() // 在原List上翻转数组元素顺序 }1.3.2 打乱元素顺序fun main() { var list1 = mutableListOf(1, 2, 3, 4, 5) var list2 = list1.shuffled() // 打乱List元素顺序, 并生成新的List list1.shuffle() // 打乱List元素顺序 }1.3.3 元素排序fun main() { var list1 = mutableListOf(3, 1, 5, 2, 4) var list2 = list1.sorted() // 从小到大排序, 并生成新的List list1.sort() // 从小到大排序 var list3 = list1.sortedDescending() // 从大到小排序, 并生成新的List list1.sortDescending() // 从大到小排序 }1.4 拼接列表元素fun main() { var list = listOf("aa", "bb", "cc") var str1 = list.joinToString() println(str1) // 打印: aa, bb, cc var str2 = list.joinToString("-", "[", "]") println(str2) // 打印: [aa-bb-cc] var str3 = list.joinToString(limit = 2, truncated = "***") println(str3) // 打印: aa, bb, *** var str4 = list.joinToString("/") { (it + it) } println(str4) // 打印: aaaa/bbbb/cccc }1.5 切片fun main() { var list1 = listOf("AA", "BBB", "CC", "DDD") var list2 = list1.slice(1..2) // [BBB, CC], 截取1,2元素 var list3 = list1.drop(2) // [CC, DDD], 丢弃前2个元素 var list4 = list1.dropLast(2) // [AA, BBB], 丢弃最后2个元素 var list5 = list1.take(2) // [AA, BBB], 截取前2个元素 var list6 = list1.takeLast(2) // [CC, DDD], 截取最后2个元素 }1.6 统计函数fun main() { var list = mutableListOf(1, 2, 3) list.sum() // 6 list.average() // 2.0 list.max() // 3 list.min() // 1 list.count() // 3 }1.7 集合运算fun main() { var list1 = listOf("AAA", "BBB") var list2 = listOf("BBB", "CCC") println(list1 + list2) // [AAA, BBB, BBB, CCC] println(list1 - list2) // [AAA] println(list1 union list2) // [AAA, BBB, CCC] println(list1 intersect list2) // [BBB] println(list1 subtract list2) // [AAA] println(list2 subtract list1) // [CCC] println((list1 - list2) union (list2 - list1)) // [AAA, CCC] }1.8 map1.8.1 mapfun main() { var list1 = listOf(5, 6, 7) var list2 = list1.map { it * it } // [25, 36, 49] }1.8.2 mapIndexedfun main() { var list1 = listOf(5, 6, 7) var list2 = list1.mapIndexed { index, value -> "[$index, $value]" // [[0, 5], [1, 6], [2, 7]] } }1.9 groupByfun main() { var list = listOf("AA", "BBB", "CC", "DDD") // {2=[AA, CC], 3=[BBB, DDD]} var map: Map<Int, List<String>> = list.groupBy { it.length } }1.10 zip1.10.1 zipfun main() { var list1 = listOf(1, 2, 3) var list2 = listOf("AAA", "BBB", "CCC") // [(1, AAA), (2, BBB), (3, CCC)] var pairs: List<Pair<Int, String>> = list1.zip(list2) }1.10.2 unzipfun main() { // [(1, AAA), (2, BBB), (3, CCC)] var pairList: List<Pair<Int, String>> = listOf( 1 to "AAA", 2 to "BBB", 3 to "CCC" ) // ([1, 2, 3], [AAA, BBB, CCC]) var listPair: Pair<List<Int>, List<String>> = pairList.unzip() }1.11 associatefun main() { var list = listOf("AAA", "BBBBB", "CCCC") // {AAA=3, BBBBB=5, CCCC=4} var map1: Map<String, Int> = list.associateWith { it.length } // {3=AAA, 5=BBBBB, 4=CCCC} var map2: Map<Int, String> = list.associateBy { it.length } // {3=AAA, 5=BBBBB, 4=CCCC} var map3: Map<String, Int> = list.associate { it to it.length } }1.12 flatten1.12.1 flattenfun main() { var list = listOf(listOf("AA", "BB"), listOf("CC", "DD")) var flatten: List<String> = list.flatten() // [AA, BB, CC, DD] }1.12.2 flatMapfun main() { var list = listOf(Container(listOf("AA")), Container(listOf("BB"))) var flatten: List<String> = list.flatMap { it.list } // [AA, BB] } class Container(var list: List<String>)1.13 chunkedfun main() { var list1 = listOf("AA", "BBB", "CC", "DDD", "E", "FF", "GGG") var list2 = list1.chunked(3) // [[AA, BBB, CC], [DDD, E, FF], [GGG]] }声明:本文转自【Kotlin】List简介。
  • [技术干货] 【Kotlin】Array简介
    1 源码public class Array<T> { public val size: Int public inline constructor(size: Int, init: (Int) -> T) public operator fun get(index: Int): T // 重载a[i]运算符 public operator fun set(index: Int, value: T): Unit // 重载a[i]=x运算符 public operator fun iterator(): Iterator<T> // 重载for(item in items)运算符 }​ 注意:数组在创建完成后,数组容量和元素类型是固定不变的,后续无法进行修改。2 创建数组2.1 创建数组​ 1)空数组var array1 = emptyArray<Int>() // 创建容量为0的数组 var array2 = arrayOfNulls<Int>(3) // 创建元素可空的数组​ 2)Array 构造方法var array1 = Array(3) { "abc" } // abc、abc、abc var array2 = Array(4) { it * it } // 0、1、4、9 var array3 = BooleanArray(3) // false, false, false var array4 = ByteArray(3) // 0, 0, 0 var array5 = ShortArray(3) // 0, 0, 0 var array6 = IntArray(3) // 0, 0, 0 var array7 = LongArray(3) // 0, 0, 0 var array8 = FloatArray(3) // 0.0, 0.0, 0.0 var array9 = DoubleArray(3) // 0.0, 0.0, 0.0 var array10 = CharArray(3) // NULL, NULL, NULL​ 3)arrayofvar array1 = arrayOf(1, 2.0, true, 'A', "abc") // Array<Any> var array2 = booleanArrayOf(true, false, true) var array3 = byteArrayOf(1, 2, 3) var array4 = shortArrayOf(1, 2, 3) var array5 = intArrayOf(1, 2, 3) var array6 = longArrayOf(1, 2, 3) var array7 = floatArrayOf(1f, 2f, 3f) var array8 = doubleArrayOf(1.0, 2.0, 3.0) var array9 = charArrayOf('A', 'B', 'C')2.2 初始化数组fun main() { var arr = arrayOf(1, 2, 3, 4, 5) arr.fill(10) // 10, 10, 10, 10, 10 }2.3 复制数组fun main() { var arr1 = arrayOf(1, 2, 3, 4, 5, 6) var arr2 = arr1.copyOf() var arr3 = arr1.copyOf(3) // 1, 2, 3 var arr4 = arr1.copyOfRange(2, 4) // 3, 4 var arr5 = arr1.sliceArray(2..4) // 3, 4, 5 var arr6 = arrayOf(1, 2, 3) + arrayOf(4, 5, 6) // 1, 2, 3, 4, 5, 6 }3 访问数组元素3.1 查找元素fun main() { var array = arrayOf("zhan", "li", "wang") println(array[1]) // 打印: li array[0] = "chen" array.any() // true, 判断数组是否为空(容量为0) array.first() // chen, 获取首个元素 array.last() // wang, 获取最后一个元素 array.indexOf("wang") // 2, 查找元素对应的索引 array.binarySearch("wang") // 2, 二分查找元素对应的索引 }3.2 遍历元素fun main() { var items = arrayOf("aa", "bb", "cc") for (item in items) { println(item) // 打印: aa、bb、cc } for (index in items.indices) { println("items[$index]=${items[index]}") // 打印: items[0]=aa、items[1]=bb、items[2]=cc } for ((index, item) in items.withIndex()) { println("items[$index]=$item") // 打印: items[0]=aa、items[1]=bb、items[2]=cc } items.forEach { println(it) // 打印: aa、bb、cc } items.forEachIndexed { index, item -> println("items[$index]=$item") // 打印: items[0]=aa、items[1]=bb、items[2]=cc } }3.3 拼接数组元素fun main() { var items = arrayOf("aa", "bb", "cc") var str1 = items.joinToString() println(str1) // 打印: aa, bb, cc var str2 = items.joinToString("-", "[", "]") println(str2) // 打印: [aa-bb-cc] var str3 = items.joinToString(limit = 2, truncated = "***") println(str3) // 打印: aa, bb, *** var str4 = items.joinToString("/") { (it + it) } println(str4) // 打印: aaaa/bbbb/cccc }4 内容比较fun main() { var arr1 = arrayOf(1, 2, 3) var arr2 = arrayOf(1, 2, 3) println(arr1.contentEquals(arr2)) // true }5 包含判断fun main() { var arr = arrayOf(1, 2, 3, 4, 5, 6) println(3 in arr) // true println(9 in arr) // false println(arr.contains(3)) // true println(arr.contains(9)) // false }6 修改元素顺序6.1 翻转元素fun main() { var arr1 = arrayOf(1, 2, 3, 4, 5) var arr2 = arr1.reversedArray() // 翻转数组元素顺序, 并生成新的数组 var list = arr1.reversed() // 翻转数组元素顺序, 并生成List arr1.reverse() // 在原数组上翻转数组元素顺序 arr1.reverse(1, 3) // 仅翻转指定下标范围内的元素 }6.2 打乱元素顺序fun main() { var arr = arrayOf(1, 2, 3, 4, 5) arr.shuffle() // 打乱数组元素顺序 }6.3 元素排序fun main() { var arr = arrayOf(3, 1, 5, 2, 4) var list1 = arr.sorted() // 从小到大排序, 并生成List arr.sort() // 从小到大排序 arr.sort(1, 4) // 从小到大排序, 仅排序指定下标范围内的元素(仅包含起点, 不包含终点) var list2 = arr.sortedDescending() // 从大到小排序, 并生成List arr.sortDescending() // 从大到小排序 arr.sortDescending(1, 4) // 从大到小排序, 仅排序指定下标范围内的元素(仅包含起点, 不包含终点) }7 可变长参数函数(vararg)7.1 常规调用fun main() { myFun("aa", "bb", "cc") // 打印: aa、bb、cc } fun myFun(vararg parms: String) { for (str in parms) { println(str) } }​ 说明:函数的可变长参数个数最多为 1 个。7.2 使用数组接收可变长参数fun main() { myFun("aa", "bb", "cc") // 打印: 3 } fun myFun(vararg parms: String) { var arr: Array<out String> = parms println(arr.size) }7.3 将数组传给可变长参数函数fun main() { var arr: Array<String> = arrayOf("aa", "bb", "cc") myFun(*arr) // 打印: 3 myFun("xx", *arr, "yy") // 打印: 5 } fun myFun(vararg parms: String) { println(parms.size) }8 统计函数fun main() { var arr = intArrayOf(1, 2, 3) arr.sum() // 6 arr.average() // 2.0 arr.max() // 3 arr.min() // 1 arr.count() // 3 }9 Array 转换为集合fun main() { var array = arrayOf("AAA", "BBB", "CCC") var list1: List<String> = array.toList() var list2: MutableList<String> = array.toMutableList() var set1: Set<String> = array.toSet() var set2: MutableSet<String> = array.toMutableSet() }10 二维数组10.1 创建数组// {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} var arr1: Array<Array<Int>> = Array(3) { Array(3) {1} } // {{1, 2}, {3, 4}} var arr2: Array<IntArray> = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4))10.2 遍历数组​ 1)通过索引遍历fun main() { // {{1, 2}, {3, 4}} var arr: Array<IntArray> = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4)) for (i in arr.indices) { for (j in arr[0].indices) { println(arr[i][j]) } } }​ 2)遍历元素fun main() { // {{1, 2}, {3, 4}} var arr: Array<IntArray> = arrayOf(intArrayOf(1, 2), intArrayOf(3, 4)) for (row in arr) { for (item in row) { println(item) } } }10.3 内容比较fun main() { // {{1, 2, 3}, {4, 5}} var arr1: Array<IntArray> = arrayOf(intArrayOf(1, 2, 3), intArrayOf(4, 5)) // {{1, 2, 3}, {4, 5}} var arr2: Array<IntArray> = arrayOf(intArrayOf(1, 2, 3), intArrayOf(4, 5)) println(arr1.contentEquals(arr2)) // false, 只比较第一层 println(arr1.contentDeepEquals(arr2)) // true, 比较每一层 }​ 声明:本文转自【Kotlin】Array简介。
  • [技术干货] 【Kotlin】扩展属性、扩展函数
    1 类的扩展​ Kotlin 提供了扩展类或接口的操作,而无需通过类继承或使用装饰器等设计模式,来为某个类添加一些额外的属性或函数,我们只需要通过一个被称为扩展的特殊声明来完成。通过这种机制,我们可以将那些第三方类不具备的功能强行进行扩展,方便我们的操作。1.1 扩展内置类1.1.1 扩展属性fun main() { var str = "abc" str.property = 5 // 打印: set property, value=5 var property = str.property // 打印: get property println(property) // 打印: 10 } var String.property: Int set(value) { println("set property, value=$value") } get() { println("get property") return 10 }​ 说明:扩展属性并不是真的往类中添加属性,也不会真的插入一个成员字段到类的定义中,导致没有变量存储我们的数据,我们只能明确定义一个 getter 和 setter 来创建扩展属性,才能让它使用起来真的像是类的属性一样。​ 如下,如果没有定义 getter 和 setter方法,将会报错如下。1.1.2 扩展函数fun main() { var str = "abc" str.myFun("xxx") // 打印: myFun, this=abc, value=xxx } fun String.myFun(value: String) { println("myFun, this=$this, value=$value") }1.2 扩展自定义类1.2.1 扩展属性​ 1)扩展新属性fun main() { var stu = Student() stu.name = "Mary" // 打印: set name, value=Mary var name = stu.name // 打印: get name println(name) // 打印: Tom } class Student var Student.name: String set(value) { println("set name, value=$value") } get() { println("get name") return "Tom" }​ 2)扩展旧属性fun main() { var stu = Student("Jack") stu.name = "Mary" // 无打印 var name = stu.name // 无打印 println(name) // 打印: Mary } class Student(var name: String) var Student.name: String // 扩展属性不会生效 set(value) { println("set name, value=$value") } get() { println("get name") return "Tom" }​ 说明:如果扩展类中的同名同类型属性,扩展将不会生效。1.2.2 扩展函数​ 1)扩展新函数fun main() { var stu = Student("Mary") stu.test() // 打印: test, name=Mary } class Student(var name: String) fun Student.test() { println("test, name=$name") }​ 2)扩展旧函数fun main() { var stu = Student("Mary") stu.test() // 打印: inner, name=Mary } class Student(var name: String) { fun test() { println("inner, name=$name") } } fun Student.test() { // 扩展函数不会生效 println("extended, name=$name") }​ 说明:如果扩展类中的同名同参函数,扩展将不会生效。1.3 重写父类的扩展函数​ 类的扩展是静态的,实际上并不会修改它们原本的类,也不会将新成员插入到类中,仅仅是将我们定义的功能变得可调用,使用起来就像真的有一样。同时,在编译时也会明确具体调用的扩展函数。1.3.1 扩展属性fun main() { var stu: Student = Student() var name1 = stu.name // 打印: Student, get name println(name1) // 打印: Mary var peo: People = stu var name2 = peo.name // 打印: People, get name println(name2) // 打印: Tom } open class People class Student: People() var People.name: String set(value) { println("People, set name, value=$value") } get() { println("People, get name") return "Tom" } var Student.name: String set(value) { println("Student, set name, value=$value") } get() { println("Student, get name") return "Mary" }1.3.2 扩展函数fun main() { var stu: Student = Student() println(stu.type()) // 打印: Student var peo: People = stu println(peo.type()) // 打印: People } open class People class Student: People() fun People.type() = "People" fun Student.type() = "Student"1.4 匿名扩展函数​ 匿名函数的使用详见 →【Kotlin】函数。fun main() { var myFun: String.() -> Int = fun String.(): Int { return this.length } println("abc".myFun()) // 打印: 3 }​ 可以使用 Lambda 表达式简化如下,Lambda 表达式的使用详见 → 【Kotlin】Lambda表达式。fun main() { var myFun: String.() -> Int = { this.length } println("abc".myFun()) // 打印: 3 }1.5 扩展函数作为参数fun main() { var len = "abc".len { this.length } println(len) // 打印: 3 } fun String.len(func: String.() -> Int): Int { return func() }2 官方扩展函数2.1 源码​ Kotlin 提供了一些泛型扩展函数(在 Standard.kt 中),如:apply、also、run、let、takeIf、takeUnless 等。​ apply、also、run、let 的区别如下,作用是执行 block 函数的内容,并且返回 T 或 block 的返回值,通常用于判空处理。函数block是否为扩展函数block入参block返回值函数返回值访问 T 对象apply是无无Tthisalso否T无Titrun是无RRthislet否TRRit2.1.1 applypublic inline fun <T> T.apply(block: T.() -> Unit): T { ... block() return this }2.1.2 alsopublic inline fun <T> T.also(block: (T) -> Unit): T { ... block(this) return this }2.1.3 runpublic inline fun <T, R> T.run(block: T.() -> R): R { ... return block() }2.1.4 letpublic inline fun <T, R> T.let(block: (T) -> R): R { ... return block(this) }2.1.5 takeIfpublic inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? { ... return if (predicate(this)) this else null }2.1.6 takeUnlesspublic inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? { ... return if (!predicate(this)) this else null }2.1.7 withpublic inline fun <T, R> with(receiver: T, block: T.() -> R): R { ... return receiver.block() }​ 说明:with 不是扩展函数,但入参 block 是扩展函数。2.1.8 topublic infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)2.1.9 toListpublic fun <T> Pair<T, T>.toList(): List<T> = listOf(first, second) public fun <T> Triple<T, T, T>.toList(): List<T> = listOf(first, second, third)2.2 应用2.2.1 apply 应用fun main() { var stu = Student() test(stu) } fun test(stu: Student?) { stu?.apply { this.name = "Tom" this.age = 23 } println(stu) // 打印: [Tom, 23] } class Student { var name: String? = null var age: Int = 0 override fun toString(): String { return "[$name, $age]" } }​ 说明:also、run、let 的应用与 apply 类似。2.2.2 takeIf 应用fun main() { var str = "ABC" var str2 = str.takeIf { it.length % 2 == 1 }?.let { it + it.reversed().substring(1) } println(str2) // 打印: ABCBA }2.2.3 with 应用fun main() { var str = "ABC" var len = with(str) { this.length } println(len) // 打印: 3 }​ 声明:本文转自【Kotlin】扩展属性、扩展函数。
  • 【Kotlin】解构函数、中缀函数
    1 解构函数1.1 解构属性fun main() { var stu = Student("Tom", 13) var (name, age) = stu println("$name, $age") // 打印: Tom, 13 var (_, age2) = stu // 只需要部分参数, 其他参数可以使用_忽略掉 } class Student(var name: String, var age: Int) { operator fun component1() = name operator fun component2() = age }1.2 解构在 Lambda 表达式中的使用​ Lambda 表达式详细介绍见 → Lambda表达式。fun main() { var stu = Student("Tom", 13) var myFun: (Student) -> Unit = {(name, age) -> println("$name, $age") } myFun(stu) // 打印: Tom, 13 } class Student(var name: String, var age: Int) { operator fun component1() = name operator fun component2() = age }2 中缀函数​ 中缀函数是使用 infix 关键字标记的函数,在使用时,可以省略点和括号,如:位运算 shl 就是一个中缀函数。函数必须满足以下条件。必须是成员函数(不是顶层函数);只能有一个参数;参数不能有默认值。​ 中缀函数调用的优先级低于算术运算符、类型转换和 rangeTo 运算符,高于布尔运算符(&&、||、is)。fun main() { var stu = Student("Tom") stu play "basketball" } class Student(var name: String) { infix fun play(str: String): Unit { println("$name play $str") } fun test() { // play "badminton" // 编译报错 this play "badminton" } }​ 说明: 如果在类中使用中缀函数,必须明确函数的调用方(接收器)。声明:本文转自【Kotlin】解构函数、中缀函数。
  • [技术干货] 【Kotlin】运算符函数
    1 一元运算符函数1.1 符号和函数符号函数+aa.unaryPlus()-aa.unaryMinus()!aa.not()a++a.dec()a--a.inc()1.2 案例fun main() { var stu = Student("Tom", 13) println(-stu) // 打印: [moT, 31] } class Student(var name: String, var age: Int) { operator fun unaryMinus(): Student { return Student(name.reversed(), age.toString().reversed().toInt()) } override fun toString(): String { return "[$name, $age]" } }2 二元运算符函数2.1 基础运算符2.1.1 符号和函数符号函数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)a in bb.contains(a)a !in b!b.contains(a)2.1.2 案例fun main() { var stu1 = Student("Tom", 13) var stu2 = Student("Mary", 18) println(stu1 + stu2) // 打印: [TomMary, 31] } class Student(var name: String, var age: Int) { operator fun plus(other: Student): Student { return Student(this.name + other.name, this.age + other.age) } override fun toString(): String { return "[$name, $age]" } }2.2 自增简化运算符2.2.1 符号和函数符号函数a += ba.plusAssign(b)a -= ba.minusAssign(b)a *= ba.timesAssign(b)a /= ba.divAssign(b)a %= ba.remAssign(b)​ 说明:如果类中同时定义了 plus 和 plusAssign 运算,a += b 就会产生歧义,因为 a += b 等价于 a = a + b,编译器不知道是执行 plus 函数还是 plusAssign 函数,就会编译报错,其他运算符同理。2.2.2 案例fun main() { var stu1 = Student("Tom", 13) var stu2 = Student("Mary", 18) stu1 += stu2 println(stu1) // 打印: [TomMary, 31] } class Student(var name: String, var age: Int) { operator fun plusAssign(other: Student): Unit { this.name += other.name this.age += other.age } override fun toString(): String { return "[$name, $age]" } }2.3 比较运算符函数2.3.1 符号和函数符号函数a > ba.compareTo(b) > 0a < ba.compareTo(b) < 0a >= ba.compareTo(b) >= 0a <= ba.compareTo(b) <= 02.3.2 案例fun main() { var stu1 = Student("Tom", 13) var stu2 = Student("Mary", 18) var res = stu1 >= stu2 println(res) // 打印: false } class Student(var name: String, var age: Int) { operator fun compareTo(other: Student): Int { return this.age - other.age } }3 括号运算符函数3.1 小括号运算符函数3.1.1 符号和函数符号函数a()a.invoke()a(i)a.invoke(i)a(i, j)a.invoke(i, j)a(i_1, ..., i_n)a.invoke(i_1, ..., i_n)3.1.2 案例fun main() { var stu = Student("Mary", 18) stu() // 打印: Mary var age = stu(1) // 打印: a println(age) // 打印: 18 } class Student(var name: String, var age: Int) { operator fun invoke(): Unit { println(name) } operator fun invoke(i: Int): Int { println(name[i]) return age } }3.2 中括号运算符函数3.2.1 符号和函数符号函数a[i]a.get(i)a[i, j]a.get(i, j)a[i_1, ..., i_n]a.get(i_1, ..., i_n)a[i] = ba.set(i, b)a[i, j] = ba.set(i, j, b)a[i_1, ..., i_n] = ba.set(i_1, ..., i_n, b)3.2.2 案例fun main() { var stu = Student("Mary") println(stu[1]) // 打印: a stu[1] = 'W' println(stu.name) // 打印: MWry } class Student(var name: String) { operator fun get(i: Int): Char { return name[i] } operator fun set(i: Int, c: Char): Unit { name = name.substring(0, i) + c + name.substring(i + 1) } }4 迭代器运算符函数​ 迭代器运算符即:for(item in items) 运算符,有以下两种实现方式。继承 Iterator 接口,实现 hasNext 和 next 函数。重载 iterator 函数,返回一个 Iterator 对象。4.1 继承 Iterator 接口fun main() { var group = Group() for (stu: Student in group) { println(stu) // 打印: [Tom, 20]、[Mary, 18] } } class Group: Iterator<Student> { private var students = arrayOf(Student("Tom", 20), Student("Mary", 18)) private var index = 0 override operator fun hasNext() = index < students.size override operator fun next() = students[index++] } class Student(var name: String, var age: Int) { override fun toString(): String = "[$name, $age]" }4.2 重载 iterator 函数fun main() { var group = Group() for (stu: Student in group) { println(stu) // 打印: [Tom, 20]、[Mary, 18] } } class Group { private var students = arrayOf(Student("Tom", 20), Student("Mary", 18)) operator fun iterator(): GroupIterator = GroupIterator() inner class GroupIterator: Iterator<Student> { private var index = 0 override operator fun hasNext() = index < students.size override operator fun next() = students[index++] } } class Student(var name: String, var age: Int) { override fun toString(): String = "[$name, $age]" }声明:本文转自【Kotlin】运算符函数
  • [技术干货] 类和对象
    1 前言​ Kotlin 是面向对象编程语言,与 Java 语言类似,都有类、对象、属性、构造函数、成员函数,都有封装、继承、多态三大特性,不同点如下。Java 有静态(static)代码块,Kotlin 没有;Java 有静态(static)函数,Kotlin 没有;Java 构造函数名与类名相同,Kotlin 构造函数名为 constructor;Kotlin 有初始化代码块(init),Java 没有;Kotlin 有主构造函数,Java 没有。​ 在包下面右键,依次点击【New → Kotlin Class/File】,输入类名后,创建 Kotlin 类文件。​ 如下,创建了一个 Student.kt 文件。package com.zhyan8.kotlinStudy class Student { }​ 笔者为简化代码,将定义的类与 main 函数放在同一个文件中了。2 类的结构​ 如下,Student 类是一个自定义的类,里面包含了一个类的基本结构。fun main() { var stu1 = Student() stu1.study() println("-----------------------------------------") var stu2 = Student("li si", 23) } class Student { private var name: String = "zhang san" // 属性 get() { // name的getter函数 return field } set(value) { // name的setter函数 field = value } private var age: Int = 18 // 属性 init { // 初始化代码块, 在构造函数前执行 println("Student init, name=$name, age=$age") } constructor() { // 无参构造函数 println("create-1, name=$name, age=$age") } constructor(name: String, age: Int) { // 有参构造函数 println("create-2, name=$name, age=$age") this.name = name this.age = age } fun study() { // 成员函数 println("study...") } }​ 说明:init 代码块可以有多个,按照从前往后的顺序执行;上述构造函数都是次要构造函数,第 3 节中会介绍主构造函数。​ 运行程序后,打印如下。Student init, name=zhang san, age=18 create-1, name=zhang san, age=18 study... ----------------------------------------- Student init, name=zhang san, age=18 create-2, name=li si, age=233 主构造函数​ 主构造函数是紧接在类名后面的构造函数,次要构造函数是类体内部定义的构造函数,它们的区别如下。主构造函数:主构造函数只能存在一个,只有函数声明,没有函数体,可以在入参中定义类的属性,会自动进行类属性的初始化赋值。次要构造函数:次要构造函数可以存在多个,可以自定义函数体,也可以无函数体,不能在入参中定义类属性,当类有主构造函数时,所有次要构造函数必须直接或间接地调用主构造函数。3.1 无参主构造函数fun main() { var stu1 = Student() println("-----------------------------------------") var stu2 = Student("zhang san") } class Student() { // 等价与: class Student constructor() init { // 初始化代码块, 在构造函数前执行 println("init") } constructor(name: String): this() { println("constructor, name=$name") } }​ 运行程序后,打印如下。init ----------------------------------------- init constructor, name=zhang san​ class Student() 等价于 class Student constructor(),如果需要对主构造函数的权限进行控制,可以修改如下。class Student private constructor() { ... }3.2 有参主构造函数(普通参数)fun main() { var stu1 = Student("xiao ming", 23) println("-----------------------------------------") // stu1.name // 编译报错, name不是成员属性 var stu2 = Student() } class Student(name: String, age: Int) { init { println("init, name=$name, age=$age") } constructor(): this("zhang san", 18) { println("constructor") } }​ 运行程序后,打印如下。init, name=xiao ming, age=23 ----------------------------------------- init, name=zhang san, age=18 constructor3.3 有参主构造函数(成员属性)fun main() { var stu1 = Student("xiao ming", 23) println("stu1.name=${stu1.name}, stu1.age=${stu1.age}") println("-----------------------------------------") var stu2 = Student() println("stu2.name=${stu2.name}, stu2.age=${stu2.age}") } class Student(var name: String, var age: Int) { init { println("init, name=$name, age=$age") } constructor(): this("zhang san", 18) { println("constructor") } }​ 说明:在主构造函数中,通过给入参添加 var(变量)或 val(常量)修饰,使得参数变为成员属性;在次要构造函数中,不能给入参添加 var 或 val 修饰。​ 运行程序后,打印如下。init, name=xiao ming, age=23 stu1.name=xiao ming, stu1.age=23 ----------------------------------------- init, name=zhang san, age=18 constructor stu2.name=zhang san, stu2.age=18​ 如果用户想修改入参属性的权限,可以在 var 或 val 前面添加权限修饰符。class Student(private val name: String, protected var age: Int) { ... }4 封装​ 封装是指将相关联的属性和函数封装到同一个类中,并且可以控制这些属性和函数的访问权限,它通过隐藏内部细节和提供清晰的接口,提高了代码的安全性、可维护性和可理解性,它是面向对象编程中的重要概念之一。​ 在 Kotlin 中,有四种访问权限修饰符:private、protected、internal 和 public。这些修饰符控制了代码中类、函数、属性等成员的可见性和访问权限。private:最严格的访问权限,只在声明它的类或文件内可见。protected:与 Java 中的 protected 类似,不同之处在于 Kotlin 中 protected 修饰的成员仅对其子类可见,但不一定在同一个文件中可见。另外,protected 在 Kotlin 中不能直接应用于顶层函数和属性(直接定义在文件中的函数和属性,而不是在类中定义的)。internal:模块内可见(模块是编译在一起的一组 Kotlin 文件),internal 修饰的成员对于同一模块中的任何其他代码都是可见的,但对于其他模块中的代码是不可见的。public:最宽松的访问权限,public 成员可以被任何地方的代码访问,如果没有指定访问修饰符,默认为 public。5 继承​ 继承是指一个类(称为子类或派生类)基于另一个类(称为父类或基类)创建新类,子类继承了父类的属性和函数,并且可以在此基础上进行扩展或修改,它是面向对象编程中的重要概念之一。在 Kotlin 中,继承使用冒号(:)来表示,Any 类是所有类的基类。​ 类的初始化顺序如下。父类主构造函数父类 init 代码块父类次要构造函数子类主构造函数子类 init 代码块子类次要构造函数5.1 子类无主构造函数fun main() { var stu = Student("zhang san", 23, 1001) } open class People(var name: String) { init { println("People init, name=$name") // 1 } constructor(name: String, age: Int): this(name) { println("People constructor, name=$name, age=$age") // 2 } } class Student : People { init { println("Student init, name=$name") // 3 (此处不能访问age和id) } constructor(name: String, age: Int, id: Int) : super(name, age) { println("Student constructor, name=$name, age=$age, id=$id") // 4 } }​ 说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错。​ 运行程序后,打印如下。People init, name=zhang san People constructor, name=zhang san, age=23 Student init, name=zhang san Student constructor, name=zhang san, age=23, id=10015.2 子类有主构造函数fun main() { var stu = Student("zhang san", 23, 1001) } open class People(var name: String) { init { println("People init, name=$name") // 1 } constructor(name: String, age: Int): this(name) { println("People constructor, name=$name, age=$age") // 2 } } class Student(name: String, var age: Int) : People(name, age) { init { println("Student init, name=$name, age=$age") // 3 (此处不能访问id) } constructor(name: String, age: Int, id: Int): this(name, age) { println("Student constructor, name=$name, age=$age, id=$id") // 4 } }​ 说明:子类必须直接或间接调用一下父类的一个构造函数,否则编译报错;当子类中有主构造函数时,子类中的次要构造函数。​ 运行程序后,打印如下。People init, name=zhang san People constructor, name=zhang san, age=23 Student init, name=zhang san, age=23 Student constructor, name=zhang san, age=23, id=10016 多态​ 多态是指同一个函数可以在不同的对象上表现出不同的行为,这种行为通常通过继承和接口来实现。多态使得代码更加灵活和可扩展,是面向对象编程中的重要概念之一。6.1 覆盖函数fun main() { var peo: People = Student("li si", 25, 1002) peo.say() } open class People(var name: String, var age: Int) { init { println("People init, name=$name, age=$age") } open fun say() { println("People say") } } class Student(name: String, age: Int, var id: Int) : People(name, age) { init { println("Student init, name=$name, age=$age, id=$id") } override fun say() { println("Student say") } }​ 运行程序后,打印如下。People init, name=li si, age=25 Student init, name=li si, age=25, id=1002 Student say6.2 覆盖属性fun main() { var peo : People = Student() peo.doSomething() } open class People { open var name: String = "zhang san" fun doSomething() { println("doSomething, name=$name") } } class Student : People() { override var name: String = "li si" }​ 运行程序后,打印如下。doSomething, name=li si6.3 类型智能转换fun main() { var peo: People = Student() // peo.study() // 编译报错 if (peo is Student) { peo.study() // 智能转换为Student } } open class People { } class Student : People() { fun study() { println("study...") } }​ 说明:Java 没有智能转换特性,需要进行强制类型转换。7 抽象类(abstract class)​ 使用 abstract 修饰的类称为抽象类,抽象类中可以有抽象属性和函数,这些属性和函数被添加了 abstract 修饰符,父类不能实现,子类必须重写实现(子类如果也是抽象类除外)。抽象类不能被实例化,只能实例化其具化子类,抽象类中允许有具化的属性和函数。fun main() { // var peo = People() // 编译报错, 抽象类不能被实例化 var stu = Student() stu.say() } abstract class People { abstract var name: String abstract fun say() } class Student : People() { override var name: String = "xiao min" override fun say() { println("$name: Hello") } }​ 说明:Java 中只有抽象函数,没有抽象属性。​ 运行程序后,打印如下。xiao min: Hello8 接口(interface)​ 接口与抽象类有些类似,接口里只有抽象属性和函数(函数允许有默认实现,属性不能),Kotlin 中允许一个类实现多个接口,但最多只能继承一个类。fun main() { var c = C("xxx", "yyy") c.aFun() c.bFun() } interface A { var x: String fun aFun() } interface B { var y: String fun bFun() } class C(override var x: String, override var y: String) : A, B { override fun aFun() { println("aFun, x=$x") } override fun bFun() { println("bFun, y=$y") } }​ 运行程序后,打印如下。aFun, x=xxx bFun, y=yyy9 枚举类型(enum class)​ 1)枚举类enum class Color(val tag: String) { RED("red") { override fun test() { println("test, $tag") } }, GREEN("green") { override fun test() { println("test, $tag") } }, BLUE("blue") { override fun test() { println("test, $tag") } }; fun printColor(): Unit { println("color=$tag") } abstract fun test() }​ 2)enumValueOf、enumValuesfun main() { var color: Color = enumValueOf<Color>("RED") var colors: Array<Color> = enumValues<Color>() println(colors.joinToString()) // RED, GREEN, BLUE }​ 3)name、ordinal、entries、valuesfun main() { println(Color.GREEN.name) // GREEN println(Color.RED.ordinal) // 0 var entries: EnumEntries<Color> = Color.entries println(entries) // [RED, GREEN, BLUE] var colors: Array<Color> = Color.values() println(colors.joinToString()) // RED, GREEN, BLUE }​ 4)自定义属性和函数fun main() { Color.RED.printColor() // color=red Color.GREEN.test() // test, green println(Color.BLUE.tag) // blue }10 数据类(data class)​ 在 class 前面添加 data 关键字表示为一个数据类,编译器会根据主构造函数中声明的所有属性自动为其生成以下函数。equals()hashCode()toString()componentN()copy()fun main() { val stu1 = Student("Zhang", 20) val stu2 = Student("Zhang", 20) // hashCode、equals println(stu1 == stu2) // true // toString println(stu1) // Student(name=Zhang, age=20) // componentN var (name, age) = stu1 println("($name, $age)") // (Zhang, 20) // copy var stu3 = stu1.copy() } data class Student(var name: String, var age: Int)​ 为了确保生成代码的一致性和有效性,数据类必须满足以下要求。主构造函数中至少有一个参数。主构造函数中的参数必须标记为 val 或 var。数据类不能是抽象的、开放的、封闭的、内部的。​ 数据类中成员函数的生成遵循以下规则。如果数据类中,equals、hashCode、toString 等函数存在显示实现,或者在父类中有 final 实现,则不会自动生成这些函数,并使用现有的实现。如果父类具有 open、componentN 函数,并返回兼容类型,则为数据类生成相应的函数,并覆盖父类的相应函数。不允许为 componentN 和 copy 函数提供显示实现。​ componentN 函数的介绍见 → 运算符函数、解构函数、中缀函数。11 内部类(inner class)​ 内部类是指在类内部申明的类,并且在 class 前面添加了 inner 申明。fun main() { var a = A() var b = a.B() b.test() } class A { private var str1 = "A-abc" private var str2 = "A-xyz" private fun fun1() { println("A-fun1") } private fun fun2() { println("A-fun2") } inner class B { private var str1 = "B-abc" private fun fun1() { println("B-fun1") } fun test() { println(str1) // B-abc println(this@A.str1) // A-abc println(str2) // A-xyz fun1() // B-fun1 this@A.fun1() // A-fun1 fun2() // A-fun2 } } }​ 声明:本文转自【Kotlin】类和对象。
  • [技术干货] 【Kotlin】Lambda表达式
    1 常规调用​ Lambda 表达式总结 中对 Java 的 Lambda 表达式进行了总结,本文将对 Kotlin 中的 Lambda 表达式进行总结。1.1 无参函数fun main() { var myFun: () -> Unit = { println("test") } myFun() // 打印: test }​ 以上代码等价于:fun main() { var myFun: () -> Unit = fun() { println("test") } myFun() // 打印: test }1.2 有参函数fun main() { var myFun: (String) -> Unit = { a -> println("test, $a") } myFun("abc") // 打印: test, abc }​ 以上代码等价于:fun main() { var myFun: (String) -> Unit = fun(a: String) { println("test, $a") } myFun("abc") // 打印: test, abc }​ 当只有一个参数时,可以使用 it 简化 Lambda 表达式,如下。fun main() { var myFun: (String) -> Unit = { println("test, $it") } myFun("abc") // 打印: test, abc }​ 如果不使用某个参数,可以使用下划线(_)简化,如下。fun main() { var myFun: (Int, Int) -> Unit = { _, b -> println("test, $b") } myFun(3, 5) // 打印: test, 5 }1.3 有返回值函数​ Lambda 表达式中最后一行将作为返回值返回。fun main() { var myFun: (Int, Int) -> Int = { a, b -> a + b } println(myFun(3, 5)) // 打印: 8 }​ 以上代码等价于:fun main() { var myFun: (Int, Int) -> Int = fun(a: Int, b: Int): Int { return a + b } println(myFun(3, 5)) // 打印: 8 }2 尾随 Lambda 表达式​ 当一个函数的最后一个参数是函数类型参数时,可以使用尾随 Lambda 表达式。2.1 无参函数fun main() { outFun { println("inFun") // 打印: inFun } } fun outFun(inFun: () -> Unit) { inFun() }2.2 有参函数fun main() { outFun { a -> println(a) // 打印: abc } } fun outFun(inFun: (String) -> Unit) { inFun("abc") }​ 当只有一个参数时,可以使用 it 简化 Lambda 表达式,如下。fun main() { outFun { println(it) // 打印: abc } } fun outFun(inFun: (String) -> Unit) { inFun("abc") }2.3 有返回值函数fun main() { outFun { a, b -> a * b // 打印: 15 } } fun outFun(inFun: (Int, Int) -> Int) { println(inFun(3, 5)) }2.4 外层函数有多个参数​ 1)尾随函数类型fun main() { outFun("abc") { println("inFun") } } fun outFun(a: String, inFun: () -> Unit) { inFun() // 打印: inFun println("outFun, $a") // 打印: outFun, abc }​ 说明:当外层函数的最后一个参数是函数类型时,可以将 {} 提到 () 外面,该语法称为“尾随 Lambda 表达式”。​ 2)非尾随函数类型fun main() { outFun({ println("inFun") }, "abc") } fun outFun(inFun: () -> Unit, a: String) { inFun() // 打印: inFun println("outFun, $a") // 打印: outFun, abc }​ 说明:当外层函数的最后一个参数不是函数类型,前面的某个参数是函数类型时,必须将 {} 写到 () 里面。3 return 使用​ Lambda 表达式中,不能直接使用 return 语句返回,需要结合标签一起使用,否则会编译报错(内联函数除外,详见 → 函数)。3.1 无返回值函数fun main() { var myFun: (Int) -> Unit = xxx@{ if (it == 3) { println("return xxx") return@xxx } println("end, $it") } myFun(3) // 打印: return xxx myFun(5) // 打印: end, 5 }3.2 有返回值函数fun main() { var myFun: (Int) -> String = xxx@{ if (it == 3) { return@xxx "test1, $it" } return@xxx "test2, $it" } println(myFun(3)) // 打印: test1, 3 println(myFun(5)) // 打印: test2, 5 }3.3 尾随函数​ 尾随 Lambda 表达式中,可以使用外层函数的名字作为 return 的标签名,也可以在 {} 前面自定义标签名。fun main() { outFun { if (it == 3) { println("inFun, return") return@outFun } println("inFun") } } fun outFun(inFun: (Int) -> Unit) { inFun(3) // 打印: inFun, return }​ 声明:本文转自【Kotlin】Lambda表达式。
  • [技术干货] 【Kotlin】函数
    1 常规函数1.1 无参函数fun main() { myFun() } fun myFun() { println("myFun") // 打印: myFun }1.2 有参函数​ 1)常规调用fun main() { myFun("myFun") // 打印: myFun } fun myFun(str: String) { println(str) }​ 2)形参指定默认值fun main() { myFun() // 打印: abc } fun myFun(str: String = "abc") { println(str) }​ 3)实参指定变量名fun main() { myFun(b = 123, a = "abc") // 打印: abc123 } fun myFun(a: String, b: Int) { println(a + b) }1.3 有返回值函数​ 1)常规调用fun main() { var c = add(3, 5) println(c) // 打印: 8 } fun add(a: Int, b: Int): Int { return a + b }​ 说明:对于无返回值类型函数,其返回类型为 Unit,如下,也可以省略不写。fun myFun(str: String): Unit { println(str) }​ 2)单行函数体简化​ 当函数内部只有一行代码时,可以简化如下。fun main() { var c = add(3, 5) println(c) // 打印: 8 } fun add(a: Int, b: Int): Int = a + b1.4 可变长参数函数(vararg)​ 1)常规调用fun main() { myFun("aa", "bb", "cc") // 打印: aa、bb、cc } fun myFun(vararg parms: String) { for (str in parms) { println(str) } }​ 说明:函数的可变长参数个数最多为 1 个。​ 2)使用数组接收可变长参数fun main() { myFun("aa", "bb", "cc") // 打印: 3 } fun myFun(vararg parms: String) { var arr: Array<out String> = parms println(arr.size) }​ 3)将数组传给可变长参数函数fun main() { var arr: Array<String> = arrayOf("aa", "bb", "cc") myFun(*arr) // 打印: 3 myFun("xx", *arr, "yy") // 打印: 5 } fun myFun(vararg parms: String) { println(parms.size) }2 函数类型变量2.1 函数类型变量​ 1)无参函数变量fun test() { println("test") } fun main() { var myFun: () -> Unit = ::test myFun() // 打印: test }​ 2)有参函数变量fun test(a: Int, b: String): Unit { println("test, $a, $b") } fun main() { var myFun: (Int, String) -> Unit = ::test myFun(123, "abc") // 打印: test, 123, abc }​ 3)有返回值函数变量fun test(a: Int, b: Int): Int { return a + b } fun main() { var myFun: (Int, Int) -> Int = ::test println(myFun(3, 5)) // 打印: 8 }2.2 匿名函数​ 匿名函数即没有名字的函数,在声明函数变量时,可以指向一个匿名函数。fun main() { var myFun: (Int, Int) -> Int = fun(a: Int, b: Int): Int { return a + b } println(myFun(3, 5)) // 打印: 8 }​ 可以使用 Lambda 表达式简化如下。fun main() { var myFun: (Int, Int) -> Int = { a, b -> a + b } println(myFun(3, 5)) // 打印: 8 }3 内联函数(inline)​ 内联函数是使用 inline 关键字修饰的函数,编译后会自动将函数体内的代码复制到调用处,以优化代码执行效率。3.1 常规内联函数​ Test.ktfun main() { myFun() } inline fun myFun() { println("内联函数") }​ 以上代码经过编译运行后,依次点击【Tools → Kotlin → Show Kotlin Bytecode】,生成字节码文件。​ 再点击 DeCompile 按钮反编译字节码文件,会生成对应的 Java 文件。public final class TestKt { public static final void main() { String var1 = "内联函数"; System.out.println(var1); } public static void main(String[] var0) { main(); } public static final void myFun() { String var1 = "内联函数"; System.out.println(var1); } }​ 说明:可以看到 myFun 函数里的代码被复制到调用处了。3.2 带 return 的嵌套内联函数​ 1)return 不带标签fun main() { outFun { println("inFun") return // 等价于: return@main } println("main end") // 未打印 } inline fun outFun(inFun: () -> Unit) { inFun() println("outFun end") // 未打印 }​ 运行结果如下。inFun​ "outFun end" 和 "main end" 未打印,这是因为内联函数会直接将 return 语句复制到 main 函数中。​ 2)return@标签fun main() { outFun { println("inFun") return@outFun } println("main end") } inline fun outFun(inFun: () -> Unit) { inFun() println("outFun end") }​ 运行结果如下。inFun outFun end main end4 泛型函数​ 泛型的类型检查只存在于编译阶段,在源代码编译之后,不会保留任何关于泛型类型的内容,即类型擦除。4.1 简单泛型函数​ 1)单泛型参数fun main() { myFun(123) // 打印: 123 myFun("abc") // 打印: abc myFun(true) // 打印: true myFun(null) // 打印: null } fun <T> myFun(param: T) { println(param) }​ 2)多泛型参数fun main() { var res: Boolean = myFun("abc", 123, true) // 打印: abc, 123 println(res) // 打印: true } fun <R, T, S> myFun(a: T, b: S, c: R): R { println("$a, $b") return c }4.2 类中泛型函数fun main() { var c1: MyClass<String> = MyClass() c1.myFun("abc") // 打印: abc var c2: MyClass<Int> = MyClass() c2.myFun(123) // 打印: 123 } class MyClass<T> { fun myFun(a: T) { println(a) } }4.3 自动推断泛型类型​ Kotlin 提供了下划线(_)运算符可以自动推断类型。fun main() { myFun<Int, _>() } fun <S : Comparable<T>, T> myFun() { println("test _") }​ Int 类和 Comparable 类的定义如下。由于 Int 继承了 Comparable,因此会自动推断 "_" 为 Int。public interface Comparable<in T> public class Int private constructor() : Number(), Comparable<Int>4.4 抗变、协变和逆变​ 1)抗变​ 如下,Int 是 Number 的子类,Number 引用可以指向 Int 对象,但是 Data 引用不能指向 Data 对象,Data 引用也不能指向 Data 对象,该现象称为抗变。​ 2)协变​ 通过 out 关键字表示 Data 引用能指向 Data 对象,类似于 java 中的 "? extends Number"。class Data<T>(var value: T) fun main() { var data1: Data<Int> = Data<Int>(1) var data2: Data<out Number> = data1 println(data2.value) // 打印: 1 // data2.value = 1 // 编译错误, setter方法被限制 }​ 说明:协变后,不能修改协变元素。使用 out 修饰的泛型不能用作函数的参数,对应类型的成员变量 setter 方法会被限制,只能当做一个生产者使用。​ 3)逆变​ 通过 in 关键字表示 Data 引用能指向 Data 对象,类似于 java 中的 "? super Int"。class Data<T>(var value: T) fun main() { var data1: Data<Number> = Data<Number>(1f) var data2: Data<in Int> = data1 println(data2.value) // 打印: 1.0 data2.value = 2 var a: Any ?= data2.value // 只能用Any接收value }​ 说明:逆变后,只能使用 Any 接收逆变元素。使用 in 修饰的泛型不能用作函数的返回值,对应类型的成员变量 getter 方法会被限制,只能当做一个消费者使用。​ 4)通配​ 在有些时候,我们可能并不在乎到底使用哪一个类型,我们希望一个变量可以接受任意类型的结果,而不是去定义某一个特定的上界或下界。在Kotlin 泛型中,星号(*)代表了一种特殊的类型投影,可以代表任意类型。class Data<T>(var value: T) fun main() { var data1: Data<Int> = Data<Int>(1) var data2: Data<*> = data1 // Data<*>等价于Data<out Any> println(data2.value) // 打印: 1.0 // data2.value = 2 // 编译错误, setter方法被限制 var a: Any ?= data2.value // 只能用Any接收value }​ 说明:由于不确定具体类型,使用时只能是 Any 类型。4.5 泛型的界​ Kotlin 泛型中,可以为其指定上界。​ 1)单上界class Data<T: Number>(var value: T) fun main() { var data1: Data<Int> = Data<Int>(1) // var data1: Data<String> = Data<String>("abc") // 编译错误, 指定了上界为Number var data2: Data<*> = data1 // Data<*>等价于Data<out Number> println(data2.value) // 打印: 1.0 // data2.value = 2 // 编译错误, setter方法被限制 var a: Number = data2.value // 可以用Number接收value }​ 2)多上界open class A {} interface B {} class Data<T>(var value: T) where T: A, T: B4.6 具化类型参数(reified)​ Kotlin 的内联(inline)函数可以使用 reified 关键字具化类型参数,允许在函数体内部检测泛型类型,因为这些类型信息会被编译器内嵌在调用点。但是,这只适用于内联函数,因为内联函数中的类型信息在编译时是可知的,并且实际类型会被编译到使用它们的地方。​ 以下调用会编译报错。​ 通过 inline 和 reified 修饰符,可以解决编译报错问题,如下。inline fun<reified T> isType(value: Any) : Boolean { return value is T } fun main() { println(isType<Int>("abc")) // 打印: false println(isType<String>("abc")) // 打印: true }​ 声明:本文转自【Kotlin】函数。
  • [技术干货] 【Kotlin】流程控制
    1 选择结构​ Kotlin 中选择结构主要包含 if -else、when 语句,并且可以返回结果。1.1 if-else1.1. 条件选择fun main() { var score = 85 if (score >= 90) { println("优秀") } else if (score >= 80) { println("良好") } else if (score >= 60) { println("及格") } else { println("不及格") } }​ 说明:如果 {} 里只有一条语句,可以省略 {},if-else 语句可以嵌套使用,其他流程控制语句也可以嵌套使用。1.1.2 条件返回​ if-else 语句也可以作为结果判断。​ 1)单行案例fun main() { var score = 85 var res = if (score > 60) "及格" else "不及格" }​ 2)多行案例fun main() { var score = 85 var res = if (score > 60) { println("恭喜您通过考试") "及格" } else { println("欢迎下次光临") "不及格" } println(res) // 及格 }​ 打印结果如下。​ 说明:返回结果需要放在 {} 中的最后一行,否则返回的是 Unit。1.2 when1.2.1 条件选择​ when 语句与 Java 中 switch 语句类似。​ 1)简单案例fun main() { var grade = 'B' when(grade) { 'A' -> { println("优秀") } 'B' -> { println("良好") } 'C' -> { println("及格") } else -> { println("不及格") } } }​ 说明:如果 {} 里只有一条语句,可以省略 {}。​ 2)多分支合并fun main() { var grade = 'B' when(grade) { 'A','B','C' -> println("及格") else -> println("不及格") } }1.2.2 条件返回​ when 语句也可以作为结果判断。​ 1)简单案例fun main() { var grade = 'B' var res = when(grade) { 'A' -> { println("你真棒") "优秀" } else -> { println("加油") "及格" } } println(res) }​ 打印结果如下。​ 说明:返回结果需要放在 {} 中的最后一行,否则返回的是 Unit。​ 2)范围分支fun main() { var score = 85 var res = when(score) { in 90..100 -> "优秀" in 80..<90 -> "良好" in 60..<80 -> "良好" else -> "不及格" } println(res) // "良好" }2 循环结构​ Kotlin 中循环结构主要包含 for、while、do-while 循环结构。另外,continue 语句可以控制跳过某次循环,break 语句可以控制跳出循环体。2.1 for​ for 循环可以对任何提供迭代器(iterator)的对象进行遍历。​ 1)遍历整数范围(IntRange、IntProgression)fun main() { for (i in 1..5) { println(i) // 打印: 1、2、3、4、5 } for (i in 5 downTo 1) { println(i) // 打印: 5、4、3、2、1 } for (i in 1..<5 step 2) { println(i) // 打印: 1、3 } }​ 2)遍历数组 / 列表fun main() { var items = arrayOf("aa", "bb", "cc") // var items = listOf("aa", "bb", "cc") for (item in items) { println(item) // 打印: aa、bb、cc } for (index in items.indices) { println("items[$index]=${items[index]}") // 打印: items[0]=aa、items[1]=bb、items[2]=cc } for ((index, item) in items.withIndex()) { println("items[$index]=$item") // 打印: items[0]=aa、items[1]=bb、items[2]=cc } }2.2 whilefun main() { var i = 0 while(i < 5) { println(i) i++ } }2.3 do-whilefun main() { var i = 0 do { println(i) i++ } while (i < 5) }2.4 continue​ 使用 continue 语句,可以跳过循环体中 continue 后面的语句,继续执行下一轮循环。​ 1)单层循环fun main() { for (i in 1..5) { if (i == 3) continue println(i) // 打印: 1、2、4、5 } }​ 2)多层循环fun main() { label@ for (i in 1..3) { for (j in 4..6) { if (j == 5) continue@label println("($i,$j)") // 打印: (1,4)、(2,4)、(3,4) } } }​ 说明:label 可以修改为任何符合变量命名规范的名字。2.5 break​ 使用 break 语句,可以跳出循环体,继续执行循环体后面的语句。​ 1)单层循环fun main() { for (i in 1..5) { if (i == 3) break println(i) // 打印: 1、2 } }​ 2)多层循环fun main() { label@ for (i in 1..3) { for (j in 4..6) { if (j == 5) break@label println("($i,$j)") // 打印: (1,4) } } }​ 说明:label 可以修改为任何符合变量命名规范的名字。​ 声明:本文转自【Kotlin】流程控制。
  • [技术干货] 变量和基本数据类型
    1 变量1.1 变量声明var a : Int // 声明整数类型变量 var b : Int = 1 // 声明整数类型变量, 同时赋初值为1 var c = 1 // 声明整数类型变量, 同时赋初值为1 val d = 1 // 声明整数类型常量, 值为1(后面不能改变d的值)​ 变量命名规范如下。变量名可以由字母、数字、下划线(_)和美元符号($)组成,但是不能以数字开头,且大小写敏感。不能有空格、@、#、+、-、/ 等符号。应该使用有意义的名称,达到见名知意的目的,最好以小写字母开头。不能与 Kotlin 语言的关键字或是基本数据类型重名。1.2 getter 和 setter方法1.2.1 自定义 getter 和 setter​ 在全局变量或类的成员变量声明时,会自动生成 getter 或 setter 方法,用户也可以重载这些方法,如下。var a : Int = 5 get() { println("get, field=$field") return field } set(value) { println("set, old-field=$field, new-field=$value") field = value } fun main() { a // 打印: get, field=5 a = 10 // 打印: set, old-field=5, new-field=10 }​ 当 getter 方法只有一行时,可以简写如下。var a : Int = 5 get() = field + 15 fun main() { println(a) // 打印: 20 }1.2.2 继承 java 的 getter 和 setter​ People.javapublic class People { public String getName() { return "zhang san"; } public void setName(String name) { System.out.println(name); } }​ Test.ktfun main() { var stu = Student() println(stu.name) // 打印: zhang san stu.name = "li si" // 打印: li si } class Student : People()​ 注意:People 中没有 name 属性,但 main 函数中可以通过 stu.name 访问到 People 的 getName 方法;如果 People 使用 Kotlin 语言编写,stu.name 会编译报错。1.3 空值1.3.1 T? 和 lateinit​ 在 Kotlin 中,对空值处理非常严格,正常情况下,变量不能直接赋值为 null,否则会编译报错。如果我们希望某个变量在初始化时赋值为 null,可以在类型名称后面添加一个问号(?)。另外,对于引用类型,如果不想在变量声明时初始化,也可以在 var 前面添加 lateinit 修饰符,表示延时初始化。fun main() { var str1: String // var str2: String = null // 编译报错 var str3: String? = null lateinit var str4: String } class A { // var str1: String // 编译报错 // var str2: String = null // 编译报错 var str3: String? = null lateinit var str4: String // var i1: Int // 编译报错 // var i2: Int = null // 编译报错 var i3: Int? = null // lateinit var i4: Int // 编译报错(基本数据类型不允许延时初始化) }1.3.2 非空断言符(!!.)​ 非空断言符(!!.)用于告诉编译器:不会出现空指针问题,不用进行空值检查,强制访问点后面的内容。fun main() { var str: String? = null // println(str.length) // 编译报错 println(str!!.length) }1.3.3 安全访问符(?.)​ 安全访问符(?.)用于告诉编译器:如果对象非空才访问点后面的内容,否则不做任何处理。fun main() { var str: String? = null // println(str.length) // 编译报错 println(str?.length) // 打印: null }1.3.4 Elvis 运算符(?:)​ Elvis 运算符(?:)用于告诉编译器:如果 ?: 前面的值为 null,就取 ?: 后面的值。fun main() { var str1: String? = null var str2: String = str1 ?: "Hello" println(str2) // 打印: Hello }2 基本数据类型2.1 空类型​ Kotlin 中空类型使用 Unit 表示,等价与 Java 中的 void。​ 1)Unit 的定义public object Unit { override fun toString() = "kotlin.Unit" }​ 2)Unit 作为变量使用fun main() { var a : Unit = Unit println(a) // kotlin.Unit }​ 3)Unit 作为函数返回值使用fun myFun() : Unit { println("定义一个没有返回值的函数") }​ 说明:当函数无返回值时,可以省略 Unit。2.2 数字类型2.2.1 整数类型类型大小(位)最小值最大值案例Byte8-128127var a: Byte = 1 var a = 1 val a = 0b1001 // 二进制 val a = 0xAF // 十六进制Short16-3276832767var a: Short = 1 var a = 1Int32-2,147,483,648 (-2^31)2,147,483,648(2^31-1)var a: Int = 1 var a = 1 var a = 1_000_000Long64-9,223,372,036,854,775,808(-2^63)9,223,372,036,854,775,807 (2^63-1)var a: Long = 1L var a = 1LUByte80255var a: UByte = 1u var a = 1uUShort16065535var a: UShort = 1u var a = 1uUInt3204,294,967,295 (2^32-1)var a: UInt = 1u var a = 1uULong64018,446,744,073,709,551,615 (2^64-1)var a: ULong = 1uL var a = 1uL var a = 0xFFF_FFF_FFFuL​ 进制表示如下。// 二进制 val a = 0b1001 // 0b是二进制前缀, 1001对应十进制的9 // 十六进制 val a = 0xAF // 0x是十六进制前缀, AF对应十进制的31​ 注意:Kotlin 没有八进制前缀表示。2.2.2 浮点类型类型大小(位)符号位(S)/ 阶码(E)/ 尾数(M)最小值/ 最大值/ 最小正数有效位数案例Float321S + 8E + 23M-3.4028235E38 3.4028235E38 1.4E-456var a: Float = 1.0F var a = 1.0F var a = 1.0fDouble641S + 11E + 52M-1.7976931348623157E308 1.7976931348623157E308 4.9E-32415var a: Double = 1.0 var a = 1.0​ 浮点数编码原理详见 → 浮点数编码原理。2.2.3 运算符运算符描述作用域优先级案例+加法整数/浮点数作为一元运算符时,优先级为1 作为二元运算符时,优先级为31 + 2 ⇒ 3-减法整数/浮点数作为一元运算符时,优先级为1 作为二元运算符时,优先级为31 - 2 ⇒ -1*乘法整数/浮点数22 * 3 ⇒ 6/整除/除法整数/浮点数23 / 2 ⇒ 1 3.0 / 2 ⇒ 1.5 3 / 2.0 ⇒ 1.5%取余整数/浮点数27 % 3 ⇒ 1++加1整数/浮点数1a++(先使用, 后加1) ++a(先加1, 后使用)--减1整数/浮点数1a--(先使用, 后减1) --a(先减1, 后使用)=赋值所有类型9a = 1+=加赋值整数/浮点数9a += 1 ⇔ a = a + 1-=减赋值整数/浮点数9a -= 2 ⇔ a = a - 2*=乘赋值整数/浮点数9a *= 3 ⇔ a = a * 3/=除赋值整数/浮点数9a /= 4 ⇔ a = a / 4%=取余赋值整数/浮点数9a %= 5⇔ a = a % 5shl有符号左移Int/Long43 shl 1 ⇒ 6 -1 shl 1 ⇒ -2 -3 shl 1 ⇒ -6shr有符号右移Int/Long43 shr 1 ⇒ 1 -1 shr 1 ⇒ -1 -3 shr 1 ⇒ -2ushr无符号右移Int/Long43 ushr 1 ⇒ 1 -1 ushr 1 ⇒ 2147483647 -3 ushr 1 ⇒ 2147483646and按位与Int/Long5// 1001 and 0011 ⇒ 0001 9 and 3 ⇒ 1or按位或Int/Long6// 1001 or 0011 ⇒ 1011 9 or 3 ⇒ 11xor按位异或Int/Long7// 1001 xor 0011 ⇒ 1010 9 or 3 ⇒ 10inv按位取反Int/Long19.inv() ⇒ -10 (-1).inv() ⇒ 0 (-3).inv() ⇒ 2..范围整数81..4 // 1, 2, 3, 4 1..5 step 2 // 1、3、5..<范围整数81..<4 // 1, 2, 3until范围整数81 until 4 // 1, 2, 3downTo范围整数83 downTo 1 // 3、2、12.3 布尔类型2.3.1 布尔类型类型大小(位)取值案例Boolean1true / falsevar a: Boolean = true var a = false2.3.2 运算符运算符描述作用域优先级案例==等于整数/布尔/字符11 == 2 // false 1 == 1 // true!=不等于整数/布尔/字符11 != 2 // true 1 != 1 // false<小于整数/浮点数/字符11 < 2 // true>大于整数/浮点数/字符11 > 2 // false<=小于等于整数/字符11 <= 2 // true>=大于等于整数/字符11 >= 2 // falsein在范围内整数/字符13 in 1..9 // true!in不在范围内整数/字符13 !in 1..9 // false!非布尔2!true // false !false // true&&与布尔3true && false // false||或布尔4true || false // true2.4 字符类型2.4.1 字符类型类型大小(位)案例Char16var a: Char = ‘A’ var a = 'A' var a = '好' var a = '\u725B' // 牛 var a = Char(66) // B var a = 'A' + 4 // E 'A'.code // 652.4.2 转义字符\t —— Tab制表符 \b —— 退格 \n —— 换行(LF) \r —— 回车(CR) \' —— 单引号 \" —— 双引号 \\ —— 反斜杠 \$ —— 美元符号2.5 字符串类型2.5.1 字符串的定义var str1 : String = "abc" var str2 = "abc" var str3 = "abc" + "def" // "abcdef" // 原始字符串 var str4 = """ 第一行 第二行 第三行 """ // 字符串模板 var count = 15 var str5 = "买了${count}个苹果" // 买了15个苹果​ 通过下标即可访问字符串中元素,如下。var str = "abc" var c1 = str[0] // 'a' var c2 = str.elementAt(1) // 'b'2.5.2 字符串函数​ Kotlin 中 String 类继承 CharSequence 类,在 _String.kt、StringsJVM.kt、StringNumberConversionsJVM.kt 等文件中定义了一些 CharSequence、String 的扩展函数。​ 1)判空// length == 0 public inline fun CharSequence.isEmpty(): Boolean // length > 0 public inline fun CharSequence.isNotEmpty(): Boolean // this == null || this.length == 0 public inline fun CharSequence?.isNullOrEmpty(): Boolean // length == 0 || indices.all { this[it].isWhitespace() } public actual fun CharSequence.isBlank(): Boolean // !isBlank() public inline fun CharSequence.isNotBlank(): Boolean // this == null || this.isBlank() public inline fun CharSequence?.isNullOrBlank(): Boolean​ 2)去掉首位空字符public inline fun String.trim(): String​ 3)查找字符public expect fun CharSequence.elementAt(index: Int): Char public inline fun CharSequence.find(predicate: (Char) -> Boolean): Char public inline fun CharSequence.findLast(predicate: (Char) -> Boolean): Char public fun CharSequence.first(): Char public inline fun CharSequence.first(predicate: (Char) -> Boolean): Char public fun CharSequence.last(): Char public inline fun CharSequence.last(predicate: (Char) -> Boolean): Char public inline fun CharSequence.random(): Char​ 4)查找字符索引public inline fun CharSequence.indexOfFirst(predicate: (Char) -> Boolean): Int public inline fun CharSequence.indexOfLast(predicate: (Char) -> Boolean): Int​ 5)过滤字符public inline fun String.filter(predicate: (Char) -> Boolean): String public inline fun String.filterIndexed(predicate: (index: Int, Char) -> Boolean): String public inline fun String.filterNot(predicate: (Char) -> Boolean): String​ 6)统计字符个数// 返回length public inline fun CharSequence.count(): Int // 统计字符串中满足条件的字符个数 public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int​ 7)字符串匹配// 判断字符串是否以xxx开头 public fun CharSequence.startsWith(char: Char, ignoreCase: Boolean = false): Boolean public fun CharSequence.startsWith(prefix: CharSequence, ignoreCase: Boolean = false): Boolean public fun CharSequence.startsWith(prefix: CharSequence, startIndex: Int, ignoreCase: Boolean = false): Boolean // 判断字符串是否以xxx结尾 public fun CharSequence.endsWith(char: Char, ignoreCase: Boolean = false): Boolean public fun CharSequence.endsWith(suffix: CharSequence, ignoreCase: Boolean = false): Boolean​ 8)获取子串public inline fun CharSequence.substring(startIndex: Int, endIndex: Int = length): String public fun String.substring(range: IntRange): String public fun String.slice(indices: IntRange): String public fun String.take(n: Int): String public fun String.takeLast(n: Int): String​ 9)字符串分割public fun CharSequence.split(vararg delimiters: Char, ignoreCase: Boolean = false, limit: Int = 0): List<String> public fun CharSequence.split(vararg delimiters: String, ignoreCase: Boolean = false, limit: Int = 0): List<String>​ 说明:字符串分割支持正则匹配,详见 → 正则表达式(Regular Expression)详解。​ 10)字串替换// 替换所有匹配的字符或字符串 public actual fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String public actual fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String // 替换第一个匹配的字符或字符串 public actual fun String.replaceFirst(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String public actual fun String.replaceFirst(oldValue: String, newValue: String, ignoreCase: Boolean = false): String // 将第一个匹配的字符或字符串前面的字符串替换为指定字符或字符串 public fun String.replaceBefore(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String public fun String.replaceBefore(delimiter: String, replacement: String, missingDelimiterValue: String = this): String // 将第一个匹配的字符或字符串后面的字符串替换为指定字符或字符串 public fun String.replaceAfter(delimiter: Char, replacement: String, missingDelimiterValue: String = this): String public fun String.replaceAfter(delimiter: String, replacement: String, missingDelimiterValue: String = this): String // 将指定索引范围的字符串替换为新字符串 public inline fun String.replaceRange(startIndex: Int, endIndex: Int, replacement: CharSequence): String public inline fun String.replaceRange(range: IntRange, replacement: CharSequence): String​ 说明:字符串替换支持正则匹配,详见 → 正则表达式(Regular Expression)详解。​ 11)字符串反转public inline fun String.reversed(): String​ 12)大小写转换// 转为大写字符串, locale可以传入Locale.ROOT public inline fun String.uppercase(locale: Locale): String // 转为小写字符串, locale可以传入Locale.ROOT public inline fun String.lowercase(locale: Locale): String​ 13)数据类型转换public actual inline fun String.toInt(): Int public actual inline fun String.toLong(): Long public actual inline fun String.toFloat(): Float public actual inline fun String.toDouble(): Double public inline fun String.toBigInteger(): java.math.BigInteger public inline fun String.toBigDecimal(): java.math.BigDecimal​ 声明:本文转自【Kotlin】变量和基本数据类型。
总条数:25 到第
上滑加载中