Kotlin学习笔记
本文只是自学kotlin所做笔记,并非全部原创
1、基本语法
var是变量,val是常量
kotlin中没有new关键字
var datas:List<String> = ArrayList()
this: kotlin中this的指定方式是在this后加上@+类名,如:
this@MainAcitivy
数组:
val names:Array = arrayOf("Kyo","Ryu","Iory")
val emptyStrings:Array = arrayOfNulls(10)
强制转换:
java写法:
TextView tv = (TextView)view.findViewById(R.id.tv);
kotlin写法:
var tv:TextView = view.findViewById(R.id.tv) as TextView
2、空校验
Kotlin有两种类型:一个是非空引用类型,一个是可空引用类型。
var s: String = null
//报错,提示“null不能是非空字符串的值”
var s: String? = null //允许为空
kotlin提供了一种方式,强制认为变量不为null,即 !!:
val srtLength = str!!.length
当然这样是不安全的,只有在你非常确定变量肯定不为空的时候,才能使用它。kotlin提供一种判断变量不为空的方法?.let{},如果非要使用!!,建议这样写:
str?.let {
val strLengh = str!!.length
}
对于可空引用,如果希望调用它的成员变量或者成员函数,直接调用会出现编译错误,有三种方法可以调用:
(1)在调用前,需要先检查,因为可能为null
(2)使用b?.length的形式调用,如果b为null,返回null,否则返回b.length
(3)使用b!!.length()的形式调用,如果b为null,抛出空指针异常,否则返回b.length
3、三元运算符
vall: Int =if(b !=null) b.length else-1
等价于
vall = b?.length ?: -1
(kotlin中if else 等价于java中的?: ,且 if else 后面可以是表达式)
4、字符串拼接
Kotlin中支持在字符串中直接使用变量
// 字符串中直接使用变量
val name ="赵四"val str: String ="你好,$name"
// 定义一个User对象
class User constructor(varname : String,varage : Int)
// 字符串中使用User对象的属性
var user: User = User("张三",23)
val toastStr: String ="这位是${user.name},今年${user.age}岁"
5、定义方法(函数)
Java 中方法需要定义到一个类当中,写法如下:
public String getString (String name){
return "张三"
}
Kotlin 中方法不一定要写在类中,写法如下:
fun getString(name:String):String{
"张三"
}
注意到返回值的位置放到了参数之后。
也可以简化成
fun getString(name:String):String= "张三"
kotlin中函数也可以是一个变量
var method = { print("我是个方法")}
6、函数的参数可以设置默认值
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
......
}
// 直接使用默认参数访问,只需要传第一个参数的值
reformat("str")
7、如何定义静态变量、方法
Java 的静态方法或者变量只需要加一个 static 即可:
public class Singleton{
private static Singleton instance = ...;
public static Singleton getInstance(){
...
return instance;
}
}
用 Kotlin 直译过来就是:
class KotlinSingleton{
companion object {
private val kotlinSingleton = KotlinSingleton()
@JvmStaticfun
getInstance() = kotlinSingleton
}
}
8、扩展函数
扩展函数是在一个类上增加一种新的行为,甚至我们没有这个类代码的权限。扩展函数的优势是它表现的像属于这个类一样,不需要传入这个类的对象,而且可以使用this关键字和调用所有public方法。
fun Activity.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(this, message, duration).show()
}
由于我们在Context上添加的这个扩展函数,那么他的子类都可以直接使用,比如在activity、fragment中,如
toast("test", 1000)
toast("test")
扩展函数并不是真正的修改了一个类,而是以静态导入的方式来实现的。扩展函数可以被声明在任何文件中,因此最好将一系列有关的扩展函数定义在一个文件中。
9、Kotlin类继承
abstract //抽象类标示
final //标示类不可继承,默认属性
enum //标示类为枚举
open //类可继承,类默认是final的
annotation //注解类
在类的构造函数之后使用“:”标示继承
class Student(name:String,age:Int):User(name,age){
}
所有类定义时默认是final属性,不可被继承。若需要继承,使用open关键字进行修饰。子类重载方法使用override关键词:
open class User{
open fun study(){}
fun run(){}
}
class Student:User{
override fun study(){}
}
当类同时继承类和实现接口,且有相同方法,且相同方法都有实现时,需要在重载方法中调用所继承的方法,使用关键词super,T表示所继承或实现的接口:
open class User{
open fun study(){}
}
interface Reading{
fun study(){}
}
class Student:User(),Reading{
override fun study(){
super.study()
super.study() //与上者至少二选其一
}
}
10、多行输入
var str = """
one
two
three
"""
//相当于
var str1 = "one"+"/n"+"two"+"/n"+"three"
11、懒加载,延迟加载
使用关键字lateinit修饰变量,延迟初始化,lazeinit只能修饰var,不能修饰val。lateinit修饰符只能修饰不可空类型,并且不允许修饰基础类型(四类八种基础类型int, double,boolean)
lateinit var test: String//正确
lateinit val test:String//错误
lateinit var test: Float//错误
使用lazy懒加载
var getCity: String by lazy {
println("成都欢迎你!")
"成都"
}
11、when,代替switch case
fun check(obj: Any) {
when(obj) {
0-> print("obj == 0")
1,2,3-> print("obj 是 1或2或3")
in3..10-> print("obj在3~10之间")
is User -> print("obj是User对象")
else-> {
print("不认识这个对象")
throwException(obj.toString())
}
}
}
12、网络请求
var text = URL(url).readText()
注意:readText不推荐结果很大的响应。
anko提供了非常简单的DSL来处理异步。doAsync函数(async函数已经弃用)用于在其他线程执行代码;uiThread则在主线程执行代码,如:
doAsync{
var text = URL(url).readText()
Log.d(javaClass.simpleName, text)
uiThread{
toast("finish")
}
}
uiThread依赖于调用者,如果它被一个activity调用,那么当activity.isFinishing()返回true,uiTread就不会调用,这样就防止了崩溃。
假如你想使用Future(java中关于线程的一个接口,用于获取结果)来工作,doAsync会返回一个Future。而如果你需要一个返回结果的Future,可以使用doAsyncResult。
13、数据类
data class Product(val date: Date, var price: Float, var detail: String)
复制数据类
如果使用不可修改对象,如果要修改某个属性必须新建一个对象,使用copy可以简化,如:
var p1 = Product(Date(), 27.5f, "tiny robot")
var p2 = p1.copy(price = 30f)
映射数据类
多声明既映射对象的每一个属性到一个变量中,如:
var p1 = Product(Date(), 27.5f, "tiny robot")
var (date, price, detail) = p1
上面这个多声明会被编译成:
var date = p1.compenent1()
var price = p1.compenent2()
var detail = p1.compenent3()
多声明可以简化代码,比如在迭代一个map时:
for((key, value) in map){
Log.d("map", "key: $key value: $value")
}