快速入门
1、资料
As查看反编译代码:
Tools -> Kotlin -> show kotlin bytecode -> Decompile
官方文档
https://kotlinlang.org/docs/reference/
Kotlin源码
https://github.com/JetBrains/kotlin
Kotlin官博
https://blog.jetbrains.com/kotlin/
Kotlin微信公众号
Kotlin
2、HelloWorld
第一种写法
fun main(args: Array<String>) {
println("Hello World")
}
第二种写法
object HelloWorld {
@JvmStatic
fun main(args: Array<String>) {
println("Hello")
}
}
第三种写法
class HelloWorld {
companion object {
@JvmStatic
fun main(args: Array<String>) {
println("Hello")
}
}
}
3、基本类型定义
var s : String = "Hello"
var stringA = "Hello"
var int = 5
基本数据类型的定义可以加类型,也可以不加。
lateinit
延迟初始化成员变量,先不赋值
private lateinit var string : String
val延迟初始化用lazy,使用的时候再赋值,值只在第一次访问的时候计算
val ss : String by lazy {
"赋值"
}
数据类型转换
.toInt()
.toFloat()
字符串比较
==
.equals()
4、定义final
const val stringB = "Hello"
val stringC = "Hello"
var
是一个可变变量,val
是一个只读变量,可以省略类型。
const
只能用在顶级属性,以及object对象的属性中(伴随对象也是obejct)。
const val
就相当于Java中的final
,编译期常量。
5、占位符"${}"
var stringG = "IamG"
var stringF = "${stringG}" + "dd"
println(stringF)//IamGdd
6、数组和遍历
val names: Array<String> = arrayOf("A", "B", "C")
val emptyStrings: Array<String?> = arrayOfNulls(10)
val array = arrayOf(1, 2, 3)
val arrayOfNulls = arrayOfNulls<Int>(3)
val array1 = Array(5) { i: Int -> (i * i).toString() }//i为索引0-4
val intArrayOf = intArrayOf(1, 2, 3)//[1,2,3]
val intArray = IntArray(3)//[0,0,0]
val intArray1 = IntArray(2) { 99 }//[99,99]
val intArray2 = IntArray(3) { it * 1 }//it为索引0-4
String?
表示可以为null的String类型
基本数据类型定制版
val ints = intArrayOf(1, 3, 5)
基本操作
names.isNotEmpty() //判断空
names.length //数组的长度
names[i] = "Hello" //给第i个成员赋值
print array[i] //输出第i个成员
for遍历(注意..
和until
)
val ints = intArrayOf(1, 3, 5, 7, 9)
for (int in ints) {
println(int)
}
for (i in ints.indices){//i是角标
print(ints[i])
}
for ((index,value) in ints.withIndex()){
println("$index -> $value")
}
for (indexedValue in strArrays.withIndex()){
println("${indexedValue.index} -> ${indexedValue.value}")
}
for (i in IntRange(0, ints.size - 1)) {
print(ints[i])
}
for (i in 0..ints.size - 1) {
print(ints[i])
}
for (i in 0 until ints.size) {
print(ints[i])
}
//Lambda方式遍历
ints.forEach{
println(it)
}
ints.forEach(::println)
ints.forEachIndexed { index: Int, i: Int -> println("$index:$i") }
ints.forEachIndexed { index, i -> println("$index:$i") }
7、list
List:
var lists = listOf <String>("张三", "李四", "王五")
for (list in lists) {
println(list)
}
for ((index, valu) in lists.withIndex()) {//角标从零开始,角标和值
println(index.toString() + "-----" + valu)
}
val list = listOf("one", "two", "one")
println(list)
val set = setOf("one", "two", "one")//不可重复
println(set)
//可变集合List
val mutableListOf1 = mutableListOf(1, 2, 3, 4)
val mutableListOf2 = mutableListOf<String>()
//可变集合Set
val hello = mutableSetOf("H", "e", "l", "l", "o")//Set自动过滤重复元素
hello.remove("o")
println(hello)
hello += setOf("w", "o", "r", "l", "d")//集合相加合并,前面的必须为可变集合
println(hello)
排序:
val number3 = mutableListOf(1, 2, 3, 4)
number3.shuffle()//洗牌,随机排序
println(number3)
number3.sort()//从小到大
println(number3)
number3.sortDescending()//从大到小
println(number3)
自定义排序:
data class Language(var name: String, var score: Int)
val languageList = mutableListOf<Language>()
languageList.add(Language("Java", 80))
languageList.add(Language("Kotlin", 90))
languageList.add(Language("Dart", 99))
languageList.add(Language("C", 80))
//使用sortBy进行排序,适合单条件排序
languageList.sortBy { it.score }
println(languageList)
languageList.sortWith(compareBy({ it.score }, { it.name }))
println(languageList)
7、map
Map:
var map = TreeMap<String, String>()
map["姓名"] = "张三"
map["性别"] = "男"
map["年龄"] = "18"
map["爱好"] = "游泳"
map不是Collection接口的继承者,但是他也是kotlin的一种集合类型:
val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 4, "key5" to 5)
println(map.keys)
println(map.values)
if ("key2" in map) println("Value by key key2:${map["key2"]}")
if (1 in map.values) println("1 is in the map")
if (map.containsKey("key1")) {
println()
}
if (map.containsValue(1)) {
println()
}
两个具有相同键值对,但顺序不同的map相等吗?为什么?
/**
* Q1:两个具有相同键值对,但顺序不同的map相等吗?为什么?
* 无论键值对的顺序如何,包含相同键值对的两个 Map 是相等的
*/
val anotherMap = mapOf("key2" to 2, "key1" to 1, "key3" to 3, "key4" to 4, "key5" to 5)
println("anotherMap == numberMap:${anotherMap == map}")
anotherMap.equals(map)
8、静态变量、方法
companion object {
}
9、方法函数
定义方法带参及返回类型
fun stringD(string : String):Boolean{
//...
return true
}
参数个数不固定,vararg:
fun stringE(vararg names: String){
}
stringE(*Ints)
简化写法
fun add(num1 : Int ,num2 : Int) : Int{
return num1 + num2
}
fun add(num1 : Int ,num2 : Int) = num1 + num2
函数作为变量使用
var d = add(1,2)
val add = fun(num1: Int, num2: Int): Int {
return num1 + num2
}
10、when表达式
when用来代替switch
fun checkScore(score: Int) : String {
var str = when (score) {
100 ->"满分"
99 -> "继续加油"
else ->"看好你哦"
}
return str
}
11、实例化类和class
实例
var data = Date()
不需要new
获得class
的实例的两种方式
val clazz1 = DD::class.java
val dd = DD()
val clazz2 = dd.javaClass
12、继承
class Son : Father(){
override fun action(){
//...
}
}
13、AS转化
as中直接转换:两次shift
后输入Convert Java File to Kotlin File
。
14、Lambda
无参数:
fun test() {
println("no param")
}
//转换成Lambda
val test = { println("no param") }
有参数:
函数入参 -> 返回值
val add = fun(num1: Int, num2: Int): Int {
return num1 + num2
}
//Lambda可以写成
val add: (Int, Int) -> Int = { a, b -> a + b }
//或者
val add = { num1: Int, num2: Int -> num1 + num2 }
过滤空后的输出结果
var strArrays = arrayOf("1", "2", "", "", "3", "4")
strArrays.filter { it.isNotEmpty() }.forEach{ println(it)}
下划线,用不到的参数可以用下划线代替:
val map = mapOf("key1" to "value1", "key2" to "value2", "key3" to "value3", "key4" to "value4", "key5" to "value5")
map.forEach { (k, _) -> println(k) }
map.forEach { (_, v) -> println(v) }
15、空安全
String?
表示可以为null的String类型。!!
表示自己判断不会出现null
,但如果出现了null
会崩溃。?
表示可能会返回null
,不会崩溃。
var string: String? = null
var len1 = string?.length
var len2 = string!!.length//最终会崩溃
16、类
类的创建
class Person(val name:String,val age:Int)
构造方法
class Person(var name: String?, var age:Int) {
constructor(name: String):this(name,0)
constructor():this(null,0)
}
get和set
var name: String? = null
private set// 私有掉set方法
var age: Int = 0
get() { return if (field < 0) 0 else field }//field就是age
类的继承
class QQStepView : View {
constructor(context:Context):this(context,null)
constructor(context:Context,attrs: AttributeSet?):this(context,attrs,0)
constructor(context:Context,attrs: AttributeSet?,defStyleAttr:Int):super(context,attrs,defStyleAttr{
// 写内容 获取自定义属性的内容
}
}
或者
class QQStepView(context: Context?, attrs: AttributeSet?) : View(context, attrs)
匿名内部类
//匿名内部类 object:xxx
httpUtils.get(object: HttpCallback(){
override fun onError(e: IOException) { }
override fun onSuccess() { Log.e("TAG","onSuccess")}
})
类内声名变量三种方式:
//1声明为空
val simple:Int?=null
//2设置getter
val simple: Int?
get() {
return 0
}
//3在构造方法内初始化
类内成员变量:
class Shop {
val name: String = "Android"
var address: String? = null
val isClose: Boolean
get() = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) > 11
var score: Float = 0.0f
//val不允许set var才可以
get() = if (field < 0.2f) 0.2f else field * 1.5f
set(value) = println(value)
var counter = 0
set(value) {
if (value > 0) field = value
}
}
/**
* lateinit 对属性的延迟初始化 常用于注入
*/
class Test {
lateinit var shop: Shop
fun setup() {
shop = Shop()
shop.address = "Beijing"
}
fun test() {
//::表示创建成员或者类的引用
if (::shop.isInitialized) println(shop.address)
}
}
17、运算符重载
class Counter(val dayIndex: Int){
// 操作符重载 +
operator fun plus(counter: Counter):Counter{
return Counter(dayIndex+counter.dayIndex)
}
// 操作符重载 -
operator fun minus(counter: Counter):Counter{
return Counter(dayIndex-counter.dayIndex)
}
}
18、方法扩展
// 对类方法进行扩展
val str = "abc"
var strMulit = str.mulit(3)
Log.e("TAG","strMulit = $strMulit")
// 对一个类的方法进行扩展
operator fun String.mulit(number: Int): String {
val stringBuilder = StringBuilder()
for (num in 1..number){
stringBuilder.append(this)
}
return stringBuilder.toString()
}
详解kotlin
1、数据类型和函数
==
和===
==
表示比较内容,类似于java的equals;===
表示比较对象是否相同。
open继承
如果一个类允许被继承,那么需要使用open声明。方法想被重写也是要加open。
open class People(name: String, sex: String) {
}
class Man(name: String, sex: String) : People(name, sex) {
}
init
init代码比构造函数先执行。
open class People(name: String, sex: String) {
init {
}
}
is
is
类似于java中的instance of
。
as父类向下转为子类
as
类型转换,失败则抛异常,as?
如果转换失败,则返回null
,不抛异常。
val child : Child? = parent as? Child
只能类型转化:父类对象直接引用子类的成员。
Any父类和Unit返回值
Any是Kotlin中的父类,类似于java中的Object。
没有返回值时候,其实返回的是Unit,相当于java中的void。
引用包名
导包时候替换其他名字
import 包名...类名1 as xxx
val name : xxx = xxx()
range
range表示范围,ClosedRange的子类
0..100 表示 [0,100]
0 until 100 表示 [0,100)
i in 0..100 判断i是否在[0,100]中
类中的toString
open class People(var name: String, var sex: String) {
override fun toString(): String {
return name + sex
}
}
get和set方法
默认已经实现了get/set方法,如果要做处理
class Woman{
var nameA : String = "翠花"
get() {
print("get方法")
return field
}
set(value) {
print("set方法")
field = value
}
}
if可以作为表达式
if可以直接作为表达式
val nameB = if (true){
"NameB"
} else {
"NameBB"
}
try...catch
、when
等也可以作为表达式。
标签
Outter@for ((index,value) in strArrays.withIndex()){
println("$index -> $value")
Inner@for (indexedValue in strArrays.withIndex()){
if (...){
break@Outter
}
}
}
接口代理
interface Child {
fun play()
}
interface Parent {
fun eat()
}
class People : Child, Parent {
override fun play() {
}
override fun eat() {
}
}
class People1(child: Child,parent: Parent) : Child by child, Parent by parent
object类
只有一个实例的类;不能自定义构造方法;可以实现接口,继承父类;本质上就是单例模式的最基本实现。object类里面的方法都是静态方法。
object FF {
val ffv : String = "ff"
}
静态方法和成员
companion object
包裹起来静态方法;@JvmStatic
和@JvmField
加上后,java去调用更方便。
class HelloWorld {
@JvmField
val TAG : String = "TAG"
companion object {
@JvmStatic
fun main(args: Array<String>) {
println("Hello")
}
}
}
方法重载
方法重载可以用方法上的默认参数代替,想给java用可以加上@JvmOverloads
。
@JvmOverloads
fun sum(a: Int = 2, b: Int): Int {
return a + b
}
data class
类
可以定义javabean,自动有了 toString()
、hashCode()
、equals()
、copy()
、componentN()
这些方法。
填坑:
apply plugin: 'kotlin-noarg'
apply plugin: 'kotlin-allopen'
classpath "org.jetbrains.kotlin:kotlin-gradle-noarg:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-allopen:$kotlin_version"
noArg{
annotation("xxxx")
}
内部类
java定义内部类,默认持有外部类的引用,除非定义为静态的内部类。
Kotlin中内部类默认是静态内部类,inner定义的是非静态内部类
inner class Inner{
}
匿名内部类
可以继承父类或者实现多个接口
interface OnClickListener {
fun onClick()
}
class View {
var onclick: OnClickListener? = null
}
val view = View()
view.onclick = object : OnClickListener{
override fun onClick() {
}
}
对象表达式
open class Address2(name: String) {
open fun print() {
}
}
class Shop2 {
var address: Address2? = null
fun addAddress(address2: Address2) {
this.address = address2
}
}
/**
* 对象表达式
*/
fun test3() {
//如果超类型有一个构造方法,则必须传递适当的构造方法参数给它
Shop2().addAddress(object : Address2("Android") {
//对象表达式
override fun print() {
super.print()
}
})
//只需要一个对象 不需要一个新的类
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
println(adHoc.x + adHoc.y)
}
2、高阶函数
对每个元素操作返回新的list
val list = listOf(1, 3, 5, 7, 9, 11)
val newList = list.map {
it * 2 + 3
}
还有
forEach、map、flatMap、reduce、fold、filter、takeWhile、
let、apply、with、use、
joinToString
尾递归
tailrec
高阶函数:如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数的话,那么该函数就称为高阶函数。
扩展函数->参考上文,18、方法扩展。
定义函数变量, ->
左边是参数类型,右边是返回值,Unit相当于void,无返回值:
val a: (String, Int) -> Unit
定义函数
fun num1Andnum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
函数作为参数
/**
* .sum扩展
*/
fun List<Int>.sum(callback: (Int) -> Unit): Int {
var result = 0
for (v in this) {
result += v
callback(v)
}
return result
}
//使用
val list = listOf(1, 2, 3, 4, 5)
var result = list.sum { println(it) }//当lambda作为参数,且只有一个参数时,可用it代替此参数
print(result)
函数作为返回值
实现一个能够对集合进行求和的高阶函数,并且返回一个(scale: Int) -> Float
的函数:
/**
* 函数作为返回值
*/
fun List<String>.toIntSum(): (scale: Int) -> Float {
println("第一层函数")
return fun(scale): Float {
var result = 0f
for (v in this) {
result += v.toInt() * scale
}
return result
}
}
//使用
val listString = listOf("1", "2", "3")
val toIntSum = listString.toIntSum()(2)
闭包
实现一个接收一个testClosure方法,该方法要接收一个Int类型的v1参数,同时能够返回一个声名为v2: Int, (Int) -> Unit
的函数,并且这个函数能够计算v1和v2的和。
fun testClosure(v1: Int): (v2: Int, (Int) -> Unit) -> Unit {
return fun(v2, printer: (Int) -> Unit) {
printer(v1 + v2)
}
}
//使用
testClosure(1)(2){
println(it)
}
解构声明
data class Result(val msg: String, val code: Int)
fun test11() {
val result = Result("success", 200)
val (msg, code) = result
println(msg + code)
}
方法字面值
var temp: ((Int) -> Boolean)? = null //变量temp为(Int)->Boolean类型
//{num->(num>10)}方法字面值
temp = { num -> (num > 10) }
println(temp(11))
3、协程
协作程序,解决异步问题。
4、泛型
fun main() {
Coke().taste()
Coke().price(Sweet())
BlueColor(Blue()).printColor()
test12()
}
//范型接口
interface Drinks<T> {
fun taste(): T
fun price(t: T)
}
class Sweet {
val price = 5
}
class Coke : Drinks<Sweet> {
override fun taste(): Sweet {
println("sweet")
return Sweet()
}
override fun price(t: Sweet) {
println("coke price=${t.price}")
}
}
//范型类
abstract class Color<T>(var t: T/*范型字段*/) {
abstract fun printColor()
}
class Blue {
val color = "blue"
}
class BlueColor(b: Blue) : Color<Blue>(b) {
override fun printColor() {
println("color:${t.color}")
}
}
//范型方法
fun <T> fromJson(json: String, tClass: Class<T>): T? {
val t: T? = tClass.newInstance()
return t
}
//范型约束
//extends
fun <T : Comparable<T>?> sort(list: List<T>?): Unit {}
fun test12() {
sort(listOf(1, 2, 3))
val listString = listOf("A", "B", "C")
val list = test(listString, "B")
println(list)
}
//多个上界
fun <T> test(list: List<T>, threshold: T): List<T>
where T : CharSequence, T : Comparable<T> {
return list.filter { it > threshold }.map { it }
}
//范型out(?extends) in(?super)
fun sumOfList(list: List<out Number>): Number {
var result = 0f;
for (number in list) {
result += number.toFloat()
}
return result
}
5、注解
fun main() {
fire(ApiGetArticles())
}
//kotlin注解
annotation class ApiDoc(val value: String)
@ApiDoc("modifier class")
class Box {
@ApiDoc("modifier field")
var size = 6
@ApiDoc("modifier func")
fun test() {
}
}
public enum class Method {
GET, POST
}
//元注解
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class HttpMethod(val method: Method)
interface Api {
val name: String
val version: String
get() = "1.0"
}
@HttpMethod(Method.GET)
class ApiGetArticles : Api {
override val name: String
get() = "/api.articles"
}
fun fire(api: Api) {
val annotations = api.javaClass.annotations
val httpMethod = annotations.find { it is HttpMethod } as? HttpMethod
println(httpMethod?.method)
}
6、扩展
fun main() {
val mutableListOf = mutableListOf(1, 2, 3)
mutableListOf.swap(0, 2)
println(mutableListOf)
val mutableListOf1 = mutableListOf("A", "B", "C")
mutableListOf1.swap1(0, 2)
println(mutableListOf1)
println("hello".lastChar)
Jump.print("dfaj")
testApply()
}
//扩展方法
fun MutableList<Int>.swap(index1: Int, index2: Int) {
var temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
//范型
fun <T> MutableList<T>.swap1(index1: Int, index2: Int) {
var temp = this[index1]
this[index1] = this[index2]
this[index2] = temp
}
//扩展属性
val String.lastChar: Char get() = this.get(this.length - 1)
//伴生对象扩展
class Jump {
companion object {}
}
fun Jump.Companion.print(string: String) {
println("Jump.Companion.print:$string")
}
/* 常见扩展 */
/**
* let
*/
fun testLet(string: String?) {
string?.let {//避免null
println(it.length)
}
string?.let {//限制作用域
val str2 = "let"
println(it + str2)
}
}
/**
* run
*/
data class Room(val address: String, val price: Float, val size: Float)
fun testRun(room: Room) {
room.run { //不再需要room.
println("Room:$address,$price,$size")
}
}
/**
* apply
* 类似与Android的builder
*/
fun testApply() {
ArrayList<String>().apply {//返回的仍为该类型的实例
add("1")
add("2")
add("3")
println("$this")
}.let { println(it) }
}
/**---------案例:使用Kotlin扩展为控件绑定监听器减少模板代码---------**/
//为Activity添加find扩展方法,用于通过资源id获取控件
fun <T : View> Activity.find(@IdRes id: Int): T {
return findViewById(id)
}
//为Int添加onClick扩展方法,用于为资源id对应的控件添加onClick监听
fun Int.onClick(activity: Activity, click: () -> Unit) {
activity.find<View>(this).apply {
setOnClickListener {
click()
}
}
}
//Activity中使用
val v = find<TextView>(R.id.test)
R.id.test.onClick(this){
test.text="Kotlin extension"
}
补充
代码:https://github.com/AdamRight/Android2021Code/tree/master/app/src/main/java/com/android/code/kotlin
1、静态函数和属性
1.1 顶层函数
顶层函数直接在kotlin文件中定义函数和属性,会直接生成静态的。
在其他kotlin类中可以直接使用函数名,在Java中通过 文件名Kt
来使用。
如果在kotlin文件中注解 @file:JvmName("类名")
,那么在Java中可以通过 类名.函数名
来使用。
1.2 object类
object类直接生成单例例对象,然后通过单例对象访问函数和属性。
在其他kotlin类中可以通过 类名.函数名
使用;在Java中通过 类名.INSTANCE.函数名
来使用。
1.3 companion object
kotlin类中使用 companion object
生成单例例对象,然后通过单例对象访问函数和属性。
在其他kotlin类中可以通过 类名.函数名
使用;在Java中通过 类名.Companion.函数名
来使用。
如果在 companion object
中的函数和属性通过 @JvmStatic
修饰,那么Java中可以用 类名.函数名
直接使用。
2、internal
有多个module模块情况下,可⻅性修饰符internal的作用是,只能被当前module模块访问的到。
3、主构造器
改造前
class User1 {
var userName: String? = null
var userPassWord: String? = null
constructor(){
}
constructor(name: String, password: String){
this.userName = name
this.userPassWord = password
}
}
改成主构造器:
class User1 constructor(name: String?, password: String?) {
var userName: String? = null
var userPassWord: String? = null
constructor() : this(null, null){
}
init {
this.userName = name
this.userPassWord = password
}
}
进一步修改:
class User1 constructor(name: String?, password: String?) {
var userName: String? = name
var userPassWord: String? = password
constructor(): this(null, null)
}
再进一步修改:
class User1 constructor(var name: String?, var password: String?) {
constructor(): this(null, null)
}
在主构造参数前面加上 var/val
使构造参数同时成为成员变量。
再进一步修改:
class User1 constructor(var name: String? = null, var password: String? = null) {
}
4、查看kotlin类的字节码
Tools –> Kotlin –> Show Kotlin Bytecode
5、Elvis操作符
通过 ?:
的操作来简化 if null
的操作。
var myName = user.name
if (myName == null){
myName = "kotlin"
}
修改后:
var myName = user.name ?: "kotlin"
修改前:
if (user.name == null || user.name!!.length < 4){
}
修改后:
if (user.name?.length ?: 0 < 4){
}
6、forEach和filter
forEach:
var arrayListUser1 = ArrayList<User1>()
var arrayListUser2 = ArrayList<User1>()
arrayListUser1.forEach {
if (it.name == "kotlin"){
arrayListUser2.add(it)
}
}
filter:
var arrayListUser1 = ArrayList<User1>()
var arrayListUser2: List<User1> = arrayListUser1.filter { it.name == "kotlin" }
7、let、apply、run、also
返回自身 –> 从 apply 和 also 中选
作用域中使用 this 作为参数 ----> 选择 apply
作用域中使用 it 作为参数 ----> 选择 also
不需要返回自身 -> 从 run 和 let 中选择
作用域中使用 this 作为参数 ----> 选择 run
作用域中使用 it 作为参数 ----> 选择 let