目录
kotlin基本数据类型, 和java一样, 全改成首字母大写
前言
关于kotlin的文章挺少的,正好公司有用到在这里分享一下,有时候写代码忘记了某一个属性或者方法,百度半天都找不到,今天就在这里记录一下,方便大家也方便自己。
基础
不管学什么语言基础很重要
常量与变量
1, 可变变量定义:var 关键字,
2, 不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)
//可变变量定义
var a = 12
a += 1//正确
//不可变变量定义
val b = 1
b = 5//报错
//和java相反, 变量名在前, 变量类型在后。
var str: String = "kotlin"//等价于var str = "kotlin"
val num :Int = 5//等价于val num = 5
函数定义和使用
//函数定义使用关键字 fun,参数格式为:参数 : 类型
fun sum(a: Int, b: Int): Int { // Int 参数类型,返回值 Int
return a + b
}
//表达式作为函数体,返回类型自动推断:
fun sum(a: Int, b: Int) = a + b
// public 方法则必须明确写出返回类型
public fun sum(a: Int, b: Int): Int = a + b
//无参函数
fun add(a:Int, b:Int):Unit{//Unit可以省略不写
println(a+b);
}
//可变长参数函数
var sum = 0
fun add(vararg v:Int, a:Int) {
for (i in 0..v.size) {
sum += i
}
println(sum + a)
}
类似于Java中的可变参数, int... num,其本身是一个数组,
和Java不同,可变参数可以放在任意参数位置。
//调用方式
add(1,2,3, a=4)//a=4为具名参数, 也就是形参
//还可以给参数设置默认值
fun add(num1:Int, num2:Int = 5){
}
//调用方式
add2(1)//不指定第二个值默认使用5
add2(1, 6)//默认值无效, 使用指定的值
add(num1=3, num3=6)//还可以这样调用
kotlin基本数据类型, 和java一样, 全改成首字母大写
// 类型转换 int和double, float, str等转换, 原理一样, 变量.toFloat() ,变量.toDouble(), 变量.toString(), 变量.toInt()
异常时, 转换原理和java一样.
var d = 15.23//Double型
var f:Float = d.toFloat()
var f1 = 12.3f
var d1 = f1.toDouble()
位操作符 和 逻辑操作符
对于Int和Long类型,还有一系列的位操作符可以使用,分别是:
//位操作符
shl(bits) – 左移位 (Java’s <<)
shr(bits) – 右移位 (Java’s >>)
ushr(bits) – 无符号右移位 (Java’s >>>)
and(bits) – 与 (&)
or(bits) – 或 (|)
xor(bits) – 异或 (^)
inv() – 取反 (~)
//逻辑操作符
|| – 短路逻辑或
&& – 短路逻辑与
! - 逻辑非
数组的常用操作符总结
1集合转换为数组
集合类提供了toIntArray()、toDoubleArray()、toFloatArray()、toBetArray()等高阶函数去处理。
val list = listOf<Int>(1,2,3,4,5,6) // 声明一个Int类型的List
val listArray = list.toIntArray() // 转换
println(list.javaClass.toString()) // 打印list的类型
println(listArray.javaClass.toString()) // 打印listArray的类型
println(listArray[1])
2.数组转换为集合
val arr = arrayOf(1,3,5,7,9)
val list = arr.toList()
3.操作类
contains(元素) : 检查集合中是否包含指定的元素,若存在则返回true,反之返回false
elementAt(index) : 获取对应下标的元素。若下标越界,会抛出IndexOutOfBoundsException(下标越界)异常,同 get(index)一样
elementAtOrNull(index) : 获取对应下标的元素。若下标越界,返回null
first() : 获取第一个元素,若集合为空集合,这会抛出NoSuchElementException异常
first{} : 获取指定元素的第一个元素。若不满足条件,则抛出NoSuchElementException异常
firstOrNull() : 获取第一个元素,若集合为空集合,返回null
firstOrNull{} : 获取指定元素的第一个元素。若不满足条件,返回null
last() : 获取最后一个元素,若集合为空集合,这会抛出NoSuchElementException异常
last{} : 获取指定元素的最后一个元素。若不满足条件,则抛出NoSuchElementException异常
lastOrNull{} : 获取最后一个元素,若集合为空集合,返回null
lastOrNull() : 同firstOrNull{}相反
indexOf(元素) : 返回指定元素的下标,若不存在,则返回-1
indexOfFirst{...} : 返回第一个满足条件元素的下标,若不存在,则返回-1
indexOfLast{...} : 返回最后一个满足条件元素的下标,若不存在,则返回-1
forEach{...} : 遍历元素。一般用作元素的打印
componentX() : 用于获取元素。其中的X代表序号, 从0开始
4.排序操作符
val list = mutableListOf<Int>(1, 34, 6, 7, 4)
// reverse()对原有集合排序,没有返回值 , reversed()返回一个新数组 : 反序。即和初始化的顺序反过来。
println(list.reversed())
// sort()对原有集合排序 sorted()排序后, 生成一个新数组 : 自然升序。
list.sort()
println(list.sorted())
// sortedBy{} : 根据条件升序,即把不满足条件的放在前面,满足条件的放在后面
list.sortBy { it < 7 }
println(list)
// sortedDescending() : 自然降序。
val list2 = list.sortedDescending()
println(list2)
// sortedByDescending{} : 根据条件降序, 即把不满足条件的放在后面,满足条件的放在前面
val list3 = list.sortedByDescending { it > 6 }
println(list3)
5.映射操作符
//map{...} : 把每个元素按照特定的方法进行转换,组成一个新的集合。一对一
val list = mutableListOf<String>("name", "password")
val list2 = list.map { it.plus("_add") }
println(list2)
//输出结果
// [name_add, password_add]
//mapNotNull{...} : 同map{}函数的作用相同,只是过滤掉转换之后为null的元素
val list3 = mutableListOf<String>("name", "password", "")
val list4 = list3.mapNotNull {
if (it.contentEquals("")) {
it.plus("_test")
} else {
it.plus("_add")
}
}
println(list4)
//输出结果
// [name_add, password_add, _test]
//mapIndexed{index,result} : 把每个元素按照特定的方法进行转换,可以操作元素的下标(index),组成一个新的集合。
val list6 = mutableListOf<Int>(1, 2, 3)
val list7 = list6.mapIndexed { index, result ->
index.toString().plus("-").plus(result)
}
println(list7)
//输出结果
// [0-1, 1-2, 2-3]
//mapIndexedNotNull{index,result} : 同mapIndexed{}函数的作用相同,只是过滤掉转换之后为null的元素
//flatMap{...} : 根据条件合并两个集合,组成一个新的集合。 一对多
val list8 = mutableListOf<Int>(1, 2, 3, 4, 5)
val list9 = list8.flatMap {
listOf(it, "a", "b")
}
println(list9)
[1, a, b, 2, a, b, 3, a, b, 4, a, b, 5, a, b]
//groupBy{...} : 分组。即根据条件把集合拆分为为一个Map<K,List<T>>类型的集合
val list10 = mutableListOf<Person>(Person("wwf", 12),
Person("alex", 12),Person("eva", 23),
Person("maggie", 23))
val map : Map<Int, List<Person>> = list10.groupBy {
it.age//以年龄来分组
}
println(map)
//输出结果
// {12=[Person(name=wwf, age=12), Person(name=alex, age=12)],
// 23=[Person(name=eva, age=23), Person(name=maggie, age=23)]}
6.过滤操作符
val list = mutableListOf<Person>(
Person("wwf", 12),
Person("alex", 12),
Person("jack", 23),
Person("eva", 23),
Person("jani", 18),
Person("maggie", 18))
//filter{...} : 把不满足条件的元素过滤掉
val list2 = list.filter { it.name.contentEquals("wwf") }
println(list2)//[Person(name=wwf, age=12)]
//filterIndexed{...} : 和filter{}函数作用类似,只是可以操作集合中元素的下标(index)
val list3 = list.filterIndexed { index, person ->
index > 1 && person.name.contentEquals("eva")
}
println(list3)
//filterNot{...} : 把满足条件的元素过滤掉, 和filter{}相反
//filterNotNull() : 过滤掉集合中为null的元素。
//take(num) : 返回集合中前num个元素组成的集合
val list4 = list.take(2)//取前两个
println(list4)
//takeWhile{...} : 循环遍历集合,从第一个元素开始遍历集合,当第一个出现不满足条件元素的时候,退出遍历。然后把满足条件所有元素组成的集合返回。
//takeLast(num) : 返回集合中后num个元素组成的集合
//takeLastWhile{...} : 循环遍历集合,从最后一个元素开始遍历集合,当第一个出现不满足条件元素的时候,退出遍历。然后把满足条件所有元素组成的集合返回。
//drop(num) : 过滤集合中前num个元素
//dropWhile{...} : 相同条件下,和执行takeWhile{...}函数后得到的结果相反
//dropLast(num) : 过滤集合中后num个元素
//dropLastWhile{...} : 相同条件下,和执行takeLastWhile{...}函数后得到的结果相反
//distinct() : 去除重复元素
//distinctBy{...} : 根据操作元素后的结果去除重复元素
val list5 = list.distinctBy { it.age }
println(list5) //[Person(name=wwf, age=12), Person(name=jack, age=23), Person(name=jani, age=18)]
//slice : 过滤掉所有不满足执行下标的元素。
val list6 = list.slice(0..3) //取前三个,和take(2)类似
println(list6)
7.生产操作符
val list1 = mutableListOf<Int>(1, 2, 3)
val list2 = mutableListOf<Int>(4, 5, 6)
//plus() : 合并两个集合中的元素,组成一个新的集合。也可以使用符号+
val list3 = list1.plus(list2)
println(list3) //[1, 2, 3, 4, 5, 6]
//zip : 由两个集合按照相同的下标组成一个新集合。该新集合的类型是:List<Pair>
val list4 = list1.zip(list2)
println(list4) // [(1, 4), (2, 5), (3, 6)]
//unzip : 和zip的作用相反。把一个类型为List<Pair>的集合拆分为两个集合。看下面的例子
val set = list1.union(list2)
println(set)
//partition : 判断元素是否满足条件把集合拆分为有两个Pair组成的新集合。
val list6 = listOf<Int>(1, 2, 3, 4, 5, 6)
val list5 = list6.partition {
it > 3
}
println(list5) //([4, 5, 6], [1, 2, 3])
8.统计操作符,Android不常用
any{...} : 判断集合中是否存在满足条件的元素。若存在则返回true,反之返回false
all{...} : 判断集合中的所有元素是否都满足条件。若是则返回true,反之则返回false
none{...} : 和all{...}函数的作用相反
max() : 获取集合中最大的元素,若为空元素集合,则返回null
maxBy{...} : 获取方法处理后返回结果最大值对应那个元素的初始值,如果没有则返回null
min() : 获取集合中最小的元素,若为空元素集合,则返回null
minBy{...} : 获取方法处理后返回结果最小值对应那个元素的初始值,如果没有则返回null
sum() : 计算出集合元素累加的结果。
sumBy{...} : 根据元素运算操作后的结果,然后根据这个结果计算出累加的值。
sumByDouble{...} : 和sumBy{}相似,不过sumBy{}是操作Int类型数据,而sumByDouble{}操作的是Double类型数据
average() : 获取平均数
reduce{...} : 从集合中的第一项到最后一项的累计操作。
reduceIndexed{...} : 和reduce{}作用相同,只是其可以操作元素的下标(index)
reduceRight{...} : 从集合中的最后一项到第一项的累计操作。
reduceRightIndexed{...} : 和reduceRight{}作用相同,只是其可以操作元素的下标(index)
fold{...} : 和reduce{}类似,但是fold{}有一个初始值
foldIndexed{...} : 和reduceIndexed{}类似,但是foldIndexed{}有一个初始值
foldRight{...} : 和reduceRight{}类似,但是foldRight{}有一个初始值
foldRightIndexed{...} : 和reduceRightIndexed{}类似,但是foldRightIndexed{}有一个初始值
单例,伴生对象,内部类
1.单例
先来看object关键字修饰下的类的形式。
object Factory
这是最简单的单例声明方法。为了更方便的了解这是单例,完整的demo代码来看下。
object Factory {
val name: String = "object single"
}
fun main(args: Array<String>) {
val factorySingle : Factory = Factory
println(factorySingle.name)
}
在object类中定义一个name成员,然后在执行入口函数main()中引用这个单例,并且打印其成员name,实际的执行结果就是在控制台打印“object single”.
...
object single
Process finished with exit code 0
在函数main()中可以看到,引用创建时,等号右则直接是类名。Kotlin中使用object关键字修饰的类将一个类声明及该类的唯一实例创建结合在一起,这个功能也叫对象声明。
2.1伴生对象
再来说本篇文章的重点,即伴生对象。伴生对象从功能上的另外一个描述:它是工厂方法和静态成员的地盘。
与Java做一个比较,Kotlin本身是不支持static关键字的,即static关键字并不是Kotlin语言的一部分。作为替代方案,Kotlin提供了包级别函数(可以在大多数情况下替代Java的静态方法)和对象声明(大多数情况下替代Java的静态方法及静态成员),多数情况下,还是推荐使用顶层函数。
重点来了,标题是伴生对象,那么怎么来声明呢 ?
在类中定义一个用特殊关键字标记的对象:companion。companion修饰的对象,使得外部可以直接通过companion容器类来访问这个对象(companion object)的属性和方法,就像Java中对静态方法和静态成员的访问形式,不需要再通过具体实例来访问。
下来看下Factory类的另外一个写法,并同样打印Factory成员name的值。
class Factory {
companion object {
const val name: String = "object single"
}
}
fun main(args: Array<String>) {
val factory : Factory = Factory()
println(Factory.name)
}
可以看到Factory对象创建依然是普通类对象的创建方式,而对name成员的访问的形式使用的是类名. 方式访问,而不是具体实例factory.name方式访问。
在标题开始,写到伴生对象的另外一种描述是:工厂方法和静态成员的地盘。
静态成员的地盘这个描述相信通过上述的示例已经可以看出一二。
下来看看工厂方法是如何来表现的呢?
创建一个User对象,根据不同的参数来获取User属性name。
学习过Java的程序员首先想到的只怕是通过不同的构造方法,传入不同参数类型来实现。相应的Kotlin中也可以采用此种方式去实现。
class User {
val name: String
constructor(name: String) {
this.name = name
}
constructor(id: Int) {
this.name = getNameBy(id)
}
private fun getNameBy(id: Int): String {
// ...
return ".."
}
}
可以使用相同逻辑,但使用工厂方法来实现。
class User private constructor(val name: String) {
companion object {
fun createUserByName(name: String): User {
return User(name)
}
fun createUserById(id: Int): User {
return User(getNameBy(id))
}
private fun getNameBy(id: Int): String {
// ...
return ".."
}
}
}
工厂方法非常有用,它可以返回声明这个方法的类的子类。但如果需要在后期扩展相关的类,那么使用多个构造方法将是更好的选择,因为伴生对象成员在子类中是不可以被重写的。
2.2做为普通对象的伴生对象
伴生对象是一个类声明中定义的普通对象。它同样有名字,可以继承类,实现接口及扩展函数和属性。
拿上述的User的伴生对象为例,为其定义一个名字。
class User private constructor(val name: String) {
companion object Factory {
fun createUserByName(name: String): User {
return User(name)
}
fun createUserById(id: Int): User {
return User(getNameBy(id))
}
private fun getNameBy(id: Int): String {
// ...
return ".."
}
}
}
fun main(args: Array<String>) {
val user: User = User.Factory.createUserById(36)
val user1: User = User.Factory.createUserByName("OK")
val user2: User = User.createUserById(54)
}
代码中可以看到,可以通过User.Factory.xxx方式来调用方法,同时也可以直接使用User.xxx方式调用方法。因为companion修改的类随即就拥有了使其外部直接使用类名来访问伴生对象的成员,因此多数情况下,不需要关心伴生对象的名称。
2.3伴生对象实现接口
伴生对象跟其他对象声明一样,可以实现接口。其调用方式就是直接使用容器类来调用接口实现,就像容器类实现了相关接口一样。
interface JSONFactory<T> {
fun loadFromJson(json: String): T
}
class User private constructor(val name: String) {
companion object Factory: JSONFactory<User> {
override fun loadFromJson(json: String): User {
// ...
return User("..")
}
// ...
}
}
在调用的时候,可以直接使用User.loadFromJson(json)方式来调用,就像是User实现了JSONFactory接口一样。
对象表达式
对象表达式就功能来说就是改变写法的匿名内部类。
这种用法取代Java的匿名内部类的写法。
熟悉Android的同志肯定了解UI事件监听写法。
view.setOnClickListener(
object: OnClickListener {
// TODO
}
);
界面跳转
我相信做安卓开发的都知道,界面跳转是必备的,在这里介绍二种跳转
1.普通跳转
val intent = Intent()
//获取intent对象
intent.setClass(this,Main2Activity::class.java)
// 获取class是使用::反射
startActivity(intent)
1.1稍微优雅一点跳转
ManagementLogActivity.startNewActivity(this)
companion object {
fun startNewActivity(context: Context) {
val intent = Intent(context, ManagementLogActivity::class.java)
context.startActivity(intent)
}
}
2.携带参数跳转
companion object {
fun startNewActivity(context: Context, title: String) {
val intent = Intent(context, ManagementLogActivity::class.java)
intent.putExtra("title", title)
context.startActivity(intent)
}
}
ManagementLogActivity.startNewActivity(this, title)
3.关于anko的用法
implementation "org.jetbrains.anko:anko:$anko_version"
3.1普通跳转
startActivity<RegisterActivity>()
3.2携带参数
startActivity<ResetPwdActivity>("key" to "值")
3.3 如果要放置多个参数,只需用逗号将其分开即可
startActivity < SomeOtherActivity >(
“ id ”到5,
“ city ”到“ Denpasar ”
)
3.4Anko具有一些广泛使用的呼叫包装器Intents