Kotlin 是一门现代但已成熟的编程语言,旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作,并提供了多种方式在多个平台间复用代码,以实现高效编程。Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。
Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。
在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。
1.内置数据类型
1.基本类型
String 字符串
Char 字符
Boolean 布尔
Int 整型
Double 浮点数
List 集合
Set 无重复的元素集合
Map 键值对的集合
fun main{
var name:string = "Array"
}
val ===> 不可改变相当于js的readonly
fun main{
var name:string = "Array"
}
const val====>编译时常量 修饰符const不能修饰局部
只能在函数之外定义
const val PI = 3.1415
fun main{
var name:string = "Array"
}
2.数字类型
Byte
Short 短整型
Int 整型
Long 长整型 可以用_表示,计数 100_000_000
var n1:Long =10L
var n2:Long =100_000_000
UByte
UShort
UInt
ULong
无符号 在后面加上u或U和长整型类似
var n3:UInt = 123u
var n4:UInt = 123U
var n5:ULong = 123UL
Float
Double
默认为Double类型,如果要使用float要加上f或者F
var m1:Float = 1.12F
var m2:Double = 1.12
var m3:Float = 1.12f
3.Boolean类型
0,false,null为假,其他为真
&& || !
4.字符类型
使用.code获取ascII码
\u转义成字符(unicode编码)
val c1:Char = 'a'
println(c1.code)
val c2:Char ='\u2C77'
println(c2)
5.字符串
用三引号包括字符串=>原始字符串
.trimIndent()去掉空格
$变量名 格式化字符串
val s2:String = """
aha
sjs
dld
kjl
""".trimIndent()
println(s2)
val s3:String = "$PI1 圆"
println(s3)
val s3:String = "${PI1} 圆" //可以用{}此时后面不用再加空格,{}里面也可以写表达式
6.运算符
与 and 或or 异或xor
shl 左移位 shr 右移位 ushr无符号右移位
2.条件语句
1.when 类似 switch
when (c) {
1 -> {
println("1")
}
2 -> {
println("2")
}
3 -> {
println("3")
}
else -> {
println("0")
}
}
2.for循环
..区间运算符20..100相当于 20 <= a <= 100
val Range1 = 5..10
val Range2 = 5..10
for (i in Range1 step 2){//一次+2
println(i)
}
for (i in 10 DownTo 1){//从10到1
println(i)
}
3.函数
函数可以嵌套使用即函数内部声明函数,在函数内部声明的函数只能在函数内部调用,并且可以使用嵌套该函数的函数体内的变量
fun main(){
outer()
}
fun outer(){
val value = 10
fun inner(){
println(value)
}
inner()
}
message:String指定形参类型
():unit指定返回值类型 unit相当于void即无返回值(可以省略不写)
fun test(message:String):Unit{
println(message)
}
设置默认值
fun test1(a:Int=3,b:Int=6):Int{
return a+b
}
//如果要指定第二个参数
test1(b=9)
简洁写法 返回值为a+b
fun test2(a:Int,b:Int) = a+b
引用函数
fun main(){
val test2 = ::test1
test2()
}
fun test1(){
println("hahha")
}
4.变量作用域
1.get set
var v:Int = 10
get() = field * 100
set(value) {
println("赋值")
field = 12
}
fun main(){
println(v)
}
5.常用库函数
var value1 = readln()
相当于Java的Scanner
//n次方
println(2.0.pow(4))
//绝对值
println(abs(value2))
//最小值
println(min(10,20))
//最大值
println(max(10,20))
//求根
println(sqrt(9.0))
//e
println(Math.E)
//pai
println(Math.PI)
println(sin(0.5*Math.PI))
println(cos(0.5*Math.PI))
println(tan(Math.PI))
println(asin(1.0));
println(acos(1.0));
println(atan(1.0));
5.函数类型变量
1.()->
1.()括号里为参数类型 ->后为返回值类型
fun main(){
val fun1:(Int)->String = outer("Hello")
val name = fun1(10)
println(name)
}
fun outer(name:String):(Int)->String{
//匿名函数
return fun(number:Int):String{
return number.toString()+"个"+name
}
}
2.可以嵌套使用
fun fu1(n1:Int,n2:Int):((String)->String,String) -> String{
}
2.lamda表达式
//it代指第一个参数
val func1:(String)->Int = {
println(it)
10 //返回的值s
}
var func:(String,String)->Int = { a,b ->
println(a)
println(b)
10
}
println(func("1","2"))
尾随lamda
fun main(){
test{
println(it)
10
}
}
fun test(func:(String)->Int){
println(func("Hello"))
}
小实验
val v1 = fu1(10,20)
val f1 = v1("Hello"){
"1"
}
println(f1)
fun fu1(n1:Int,n2:Int):(String,(String)->String) -> String{
println(n1+n2)
return fun(s2:String, fun2:(String)->String):String{
return fun2("1234")+s2
}
}
如果函数调用的是尾随的lamda则标签名字就是函数的名字
val fun2:(Int) -> Int = mytest@{
if (it >10 ) return@mytest 10
20
}
3.内联函数
1.声明内联函数
编译之后将函数原封不动加入到调用的位置
inline fun mytest() = {
println("1")
}
高阶函数使用lamda
内联高级函数的lamda参数可以直接写return不指定标签
fun main(){
mytest {
return //内联高级函数的lamda参数可以直接写return不指定标签
}
println("Hi")
}
inline fun mytest(func: (String) -> Int):Unit{
println("1")
func("2")
}
在不需要内联的函数形参上添加noinline关键字,可以防止函数调用内联
标签可以指定为外部的函数名称
6.类和对象
1.类的创建
var 可改
val 不可改
class Student constructor(var name:String,val age:Int){
}
如果在类中定义,要赋值
class Student {
var name:String = "Jack"
var age:Int = 18
}
class Student(name:String,age:Int) {
var name:String = name
var age:Int = age
}
懒加载,在使用之前必须初始化
class Teacher{
lateinit var name: String
lateinit var age:Integer
}
2.对象的创建
val s1 = Student("Jerry",44);
println(s1.age)
println(s1.name)
s1.name = "Tom"
println(s1.name)
constructor
当类有主构造函数是,其他次要构造函数都要调用主构造函数
主构造函数可以省略constructor不写
//主构造函数
class Student1(var name:String,var age:Int){
//次要构造函数
constructor(name:String):this(name,90)
}
class Student1{
constructor(name:String)
}
3.对象的初始化
在创建对象时会执行init里的代码
可以写多个init 相当于主构造函数的函数体
class Teacher1(var name:String,var age:Int){
init {
println("创建成功")
}
}
4.基本数据类型常用方法
val v1:String = "10"
println(v1.toInt())
val v2:String = "samll"
println(v2.uppercase())
val v3:String = "BIG"
println(v3.lowercase())
val v4:String = "how are you"
println(v4.replace('o','m'))
//获取长度(字符串)
println(v4.length)
5.运算符重载
重载二元运算符 +
class Student constructor(var name:String,var age:Int){
operator fun plus(another:Student):Student{
return Student(this.name+another.name,another.age+this.age)
}
}
重载一元运算符 !
operator fun not():Student{
return Student(this.name.reversed(),this.age)
}
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a– a.dec()
a++ a.inc()
operator fun inc():Student{
return Student(name,age++)
}
operator fun dec():Student{
return Student("name",age++)
}
a+=b a.plusAssign(b)
a-=b a.minusAssign(b)
a*=b a.timesAssign(b)
a/=b a.divAssign(b)
a%= b a.remAssign(b)
同时定义+和+=可能会产生歧义
a>b a.compareTo(b) >0
a<b a.compareTo(b) <=0
a>=b a.compareTo(b) >0
a<=b a.compareTo(b) <=0
() invoke
6.中缀函数
println(10 shl 2) 左移位
调用可以省略点和括号
要求:
1.必须是成员函数
2.只能有一个参数
3,参数不能有默认值
class Student constructor(var name:String,var age:Int){
operator fun plus(another:Student):Student{
return Student(this.name+another.name,another.age+this.age)
}
operator fun not():Student{
return Student(this.name.reversed(),this.age)
}
operator fun inc():Student{
return Student(name,age++)
}
operator fun dec():Student{
return Student("name",age++)
}
infix fun test(string:String):String{
return name+string
}
}
package demo2
fun main(){
val stu = Student("zs",11)
println(stu test "hahaha")
//也可以当成普通函数调用
println(stu.test("hahaha"))
}
7.空值和空类型
当我们直接给一个变量赋值空null是kotlin在编译阶段就会报错
val ss:String = null
加上?:表明这是一个可空的类型
val ss:String ?= null
加上!!强制调用
ss!!.getdata()
安全访问方法
ss?.getdata()
val s:Student? = null
val a = s?.getdata() ?: "hahah"
println(a)
?: 类似与三元运算符 ,当对象为空是会执行?:右边的函数
8.解构
component1即为第一个解构的参数
解构()里的变量名可随意取
class Car(var name:String,var price:Int) {
operator fun component1() = name
operator fun component2() = price
}
fun main(){
val car:Car = Car("ll",1000)
val (a,b) = car
println(a)
println(b)
//如果不需要第一个解构的值
val (_,b) = car
}
应用-》在lamda表达式中使用
val func1:(Car)->String = { (a,b) ->
a+b.toString()
}
println(func1(car))
7.类与继承
1.权限声明
public
private
protected
internal 只能在当前项目内访问,当别人引用我们的项目时,不能使用
2.类的继承
声明继承
被继承的类要要声明open
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}
public class SuperCar:Car("1",1000){
}
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}
public class SportCar(name:String,price: Int):Car("1",1000){
}
当子类未声明主构造函数
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
}
public class SportCar:Car{
constructor(name:String,price: Int):super("1",1000)
}
3.方法的重写(覆盖)
可以通过super关键字调用父类的方法
public open class Car(internal var name:String, public var price:Int) {
operator fun component1() = name
operator fun component2() = price
open fun run(data:String){
println(data+"1")
}
}
public class SuperCar:Car("1",1000){
override fun run(data: String) {
super.run(data)
}
}
重写成员变量
public open class Car() {
open var name:String = "zs"
}
public class sportcar: Car(){
override var name: String = "ls"
}
4.顶层Any类
相当于java的Object
=== 判断是否是同一个引用对象
5.抽象类
abstract class annimal{
abstract var name:String
abstract fun say()
}
class cat(override var name: String) :annimal(){
override fun say() {
println("miao")
}
}
abstract class annimal{
abstract var name:String
abstract fun say()
}
class cat :annimal(){
override var name:String = "cat"
override fun say() {
println("miao")
}
}
6.接口
接口的所有成员变量和类方法都是抽象的,因此可以省略abstract不写
interface A{
val name:String
fun run1():String
}
interface B{
val age:Int
fun run2():String
}
class stu() :A,B{
override val age: Int = 16
override val name: String ="NAME"
override fun run1(): String {
return "1"
}
override fun run2(): String {
return "2"
}
}
接口也可以实现默认方法
interface A{
val name:String
fun run1():String
}
interface B{
val age:Int
fun run2():String = "AGE"
}
class stu() :A,B{
override val age: Int = 16
override val name: String ="NAME"
override fun run1(): String {
return "1"
}
override fun run2(): String {
return "2"
}
}
如果继承的两个接口有重复函数可以使用<>消除歧义
interface A{
fun run():String = "NAME"
}
interface B{
fun run():String = "AGE"
}
class stu() :A,B{
override fun run(): String = super<A>.run();
override fun run(): String = super<B>.run();
}
7.类的扩展
class animal{
fun test(){
println("HAHAHA")
}
}
fun animal.test() = println("HELLO")
fun main(){
animal().test()
}
当有重复函数是扩展会失效
添加属性,此时field无法使用
类的扩展会受到访问权限的影响
var animal.NAME: String
get() = ""
set(value){
println("SET")
}
在扩展的函数中可以直接使用类的成员变量,可以不使用this关键字
class animal{
val name:String = "JKL"
}
fun animal.test() = {
println(name)
}
指定调用的函数
class A{
fun hello(){
println("Hello")
}
}
class B(private val a:A){
fun A.test(){
hello()
this.hello()
this@B.hello()
}
fun hello(){
println("HELLO")
}
}
将一个扩展函数作为参数传递到一个函数类型变量,在具体操作前要增加类型名称
fun main(){
val func:String.() -> Int = {
this.length
}
println("hahahahhaha".func())
println(func("hello"))
}
8.范型
1.范型
可以直接接收数值,自动转换类型
class Score<T>(var name:T){
}
fun main(){
val stu = Score("123")
}
2.官方高阶扩展函数
apply 传入一个lambda表达式,也就是我们要如何操作这个对象
let 执行一个lamda表达式并将得到的结果作为返回值
also 与apply类似
run 与let类似
fun main(){
val a:Any = Any()
a.apply { }
}
3.协变和逆变
class Num<T>(var name:T)
fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<Number> = v1 //报错
}
虽然Number是Int的父类但是缺类型不匹配
协变 父类接收子类
逆变 子类接收父类
抗变 类型不相关Test<Int>与Test<Number>无关
使用out开启协变,使用in开启逆变
//协变
class Num<T>(var name:T)
fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<out Number> = v1
}
//逆变
class Num<T>(var name:T)
fun main(){
val v1:Num<Any> = Num<Any>(1)
val v2:Num<in Number> = v1
}
可以使用*来代指任意类型
4.范型的界限
限制范型的类型
//限制上界为Number
class Num<T : Number>(var name:T)
fun main(){
val v1:Num<Int> = Num<Int>(1)
val v2:Num<out Number> = v1
}
class Num<T>(var name:T)
where T:C,T:D
open class C
open class D
也可以直接在类或接口的参数中声明
interface Test<out T>{
fun test():T
}
5.类型擦除
内联函数的类型擦除与普通函数的
reified通过该关键字具化类型
inline fun <reified T> test(value:Any):Boolean{
return value is T
}
fun main(){
val result = test<String>("1")
println(result)
}
9.数组
1.定义和遍历数组
fun main(){
val array:Array<Int> = arrayOf(1,2,3,4,6,5)
for (element in array){
println(element)
}
}
获取长度 array.size
数组在创建完成后数组容量和元素类型是固定不变的后续无法修改
fun main(){
val array:Array<Int> = arrayOf(1,2,3,4,6,5)
//遍历下标和元素
for ((index,element) in array.withIndex()){
println(array[index])
println(index)
println(element)
}
}
数组的创建和使用
array.forEach { println(it) }
//第一个参数为间隔符,第二个参数为开始字符串,第三个为结束字符串
println(array.joinToString(",","[","]"))
//创造一个长度为5,值都为123的字符串数组
val array:Array<String> = Array(5){"1234"}
2.数组的操作
==号判断内容是否相同
val array1:Array<String> = Array(5){"1234"}
val array2:Array<String> = Array(5){"1234"}
println(array1.contentEquals(array2)) //=>true
拷贝数组
可以指定参数,为拷贝的数量如果数量大于数组大小会用空填充
//执行拷贝
var array3:Array<String> = array2.copyOf()
//指定拷贝范围
var array4:Array<String> = array2.copyOfRange(2,3)
分割数组
var array5:Array<String> = array2.sliceArray(1..3)
数组可以用加号进行合并
判断指定元素在不在数组
array2.contains("1234")
"1234" in array2
快速查找元素在哪一位置
array2.indexOf("1234")
reversedarray反转数组
sort排序 sortDesc倒排序
可以重写一个类的compareTo方法指定排序规则
class B():Comparable<B>{
override fun compareTo(other: B): Int {
return B.age - A.age
}
}
vararg 可以接收任意个同类型的参数
3.基本数组类型
Kotlin Java
ByteArray byte[]
CharArray char[]
ShortArray short[]
IntArray int[]
LongArray long[]
DoubleArray double[]
FloatArray float[]
BooleanArray boolean[]
4.List
可变的列表,可以插入和删除
fun main(){
val list:MutableList<String> = mutableListOf("1","2","3");
list.add("4")
list.add(1,"5")
list.remove("1")
list.removeAt(1)
println(list)
}
不可变的列表,无法插入删除
val list1:List<Int> = listOf(1,2,3)
可以用{}进行初始化赋值
使用for in 进行遍历
val list2:List<Int> = List<Int>(3){10}
for (ele in list2){
println(ele)
}
5.Set
没有重复元素,可用于去重
不能在指定位置插入
var set:MutableSet<Int> = mutableSetOf(1,2,3)
//简单的获取元素
println(set.elementAt(0))
集合的运算
//并集
println(set1 union set2)
println(set1 + set2)
//交集
println(set1 intersect set2)
//差集
println(set1 - set2)
println(set1 subtract set2)
不同类型的set
val set1:SortedSet<Int> = sortedSetOf(9,5,3,19) //自动排序
println(set1)
val set2:HashSet<Int> = hashSetOf(1,2,3) // 无序且不重复
println(set2)
6.Map
Pair
val pair:Pair<Int,String> = 10001 to "zs"
创建Map
map[键]获取值
val map:MutableMap<Int,String> = mutableMapOf(
1001 to "zs",
1002 to "ls"
)
//获取所有的键
println(map.keys)
//获取所有的值
println(map.values)
遍历
for in
for each
map.forEach{(k,v) -> println(k.toString()+v) }
可以直接+=添加新键值对
键不能重复,否则数据会被覆盖
map.put()
map.putAll()
7.迭代器
val iterator:Iterator<String> = array1.iterator()
println(iterator.next())
println(iterator.next())
println(iterator.next())
println(iterator.next())
遍历数组
val iterator:Iterator<String> = array1.iterator()
while(iterator.hasNext()){
println(iterator.next())
}
ListIterator可以实现双向遍历
MutableIterable迭代器 可以在遍历的时候进行删除
8.数组的扩展操作
map 类似于js的map对每一个元素进行操作并且返回一个值
val list:MutableList<String> = mutableListOf("AAA","BB","DDD")
val list2 : MutableList<Int> = list.map { it.length }.toMutableList()
println(list2.joinToString())
遍历map
val map:Map<String,Int> = mapOf(
"AAA" to 1,
"BB" to 2,
"CCCC" to 3
)
val map1: Map<Int, Int> = map.mapKeys { it.key.length }
val map2 : Map<String,String> = map.mapValues { it.value.toString() }
zip
unzip
val zipmap: List<Pair<String, Int>> = list1.zip(list2)
println(zipmap)
val pair:Pair<List<String>, List<Int>> = zipmap.unzip()
println(pair)
associate将列表映射为一个map集合
val associates : Map<String,Int> = list1.associate { it to it.length }
println(associates)
扁平化处理多维数组
val array= Array(10, {Array(10){0}})
val list = List(10,{List(10){0} })
//展平
println(array.flatten())
array.flatMap { }在遍历的同时映射
filter过滤操作
list1.filter { it >= 10 }
//过滤不为空的元素
list1.filterNotNull()
10.序列
在使用时才会执行其中的语句
val sequence:Sequence<Int> = generateSequence {
println("构造")
10 //返回值
}
println(sequence.iterator().next())
普通的list,在执行操作时就会调用函数
val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.filter {
println("执行1")
it.length > 2
}.map {
println("执行2")
it.lowercase()
}.take(2)
println(result)
进行优化,在调用使用的时候才会执行内部
数据量庞大时推荐使用
val list:List<String> = mutableListOf("AAA","BB","CCC","dd","EEE","FF")
val result = list.asSequence().filter {
println("执行1")
it.length > 2
}.map {
println("执行2")
it.lowercase()
}.take(2)
println(result.joinToString())
11.特殊的类型
1.数据类型
本质是class
data class Data(val name:String,val age:Int){
}
加上data关键字后
自动生成.equals()/.hashCode()
.toString()
.componentN()
.copy()方法
数据类不能是抽象类
主构造函数必须有一个参数
主构造函数变量必须是var或者val
编译器只会根据构造函数生成,因此可以将参数移出主构造函数,equals方法就不会考虑到写在主构造函数之外的变量
2.枚举类型
加上enum关键字
枚举类可以重写内部的抽象函数,当继承了一个接口时,可以在每个枚举类中重写,或者在定义枚举类的类中重写
fun main(){
println(Status.ERR.code)
}
enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2")
}
可以定义成员函数
fun main(){
val status = Status.ERR
println(status.code)
println(status.isERR())
}
enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2"); //使用;进行分隔
fun isERR() = this == ERR
}
定义成员变量
fun main(){
println(status.state)
}
enum class Status(var code:String){
ERR("0"),SUCC("1"),COMP("2");
val state:Int = 10
}
使用when
val message:String = when(status){
Status.ERR -> "错误"
Status.SUCC -> "成功"
Status.COMP -> "运行"
}
println(message)
entries获取整个枚举类
val statuslist = Status.entries
println(statuslist.joinToString())
12.匿名类
1.匿名类
使用object关键字声明匿名类,并且可以用变量接收
fun main(){
val stu = object {
fun test():String{
return "123"
}
}
val message = stu.test()
println(message)
}
如果接口只有一个函数,可以采用简洁写法实现匿名类
fun interface Krunnerable{
fun test()
}
fun main(){
val stu = object {
fun test():String{
return "123"
}
}
val message = stu.test()
println(message)
val runnerable = Krunnerable{
println("1234")
}
}
单例对象
object Run{ 通过objext关键字
val name:String = "name"
override fun toString(): String {
return super.toString()
}
}
fun main(){
val run = Run //单例对象直接使用类型得到实例化对象
println(run.toString()) //可以直接使用内部的方法
}
2.伴生对象
companion
class Animal(val name:String){
//使用companion 关键字定义半生对象
companion object Cat{
val age:Int = 90
fun test(){
println("test")
}
}
}
fun main() {
//可以直接使用外面的类名访问内部的方法
Animal.test()
}
13.委托模式
使用by关键字
//定义接口
interface Base{
fun test()
}
//接口实现
class BaseImpl():Base{
override fun test() {
println("test")
}
}
//委托代理
class Work(val base:BaseImpl) : Base by base //实现Base接口,但是让base帮忙重写
fun main() {
//可以直接使用外面的类名访问内部的方法
val work = Work(BaseImpl())
work.test()
}
使用预设代理lazy在调用时赋值
class Exe(){
val per:String by lazy { "geren" }
}
fun main() {
val message:String = Exe().per
println(message)
}
属性可以委托属性代理
class Exe1(val name:String){
val per:String by ::name
}
设置观察者
//设置观察者
class Exe2(val name:String){
val per:String by Delegates.observable("初始值"){
prop,new,old -> println("属性值为${prop},新值为${new},旧值为${old}")
}
}
14.密封对象
sealed class A
不能在外部继承使用以及实例化(模块内部)
密封类是可以被继承的,密封类的子类也可以是密封类
15.异常机制
1.异常的定义
Exception in thread "main" java.lang.ArithmeticException: / by zero
at demo1.Test5Kt.div(test5.kt:47)
at demo1.Test5Kt.main(test5.kt:42)
at demo1.Test5Kt.main(test5.kt)
自定义Exception
class myException(override val message: String?):Exception(message)
private fun div(x:Int, y:Int):Int{
if (y==0) throw myException("div by zero")
return x / y
}
2.捕获异常
val array:MutableList<Int> = mutableListOf(1,2,9)
try{
println(array[3])
}catch (e:IndexOutOfBoundsException){
e.printStackTrace()
}
println("after")
多个catch
val array:MutableList<Int> = mutableListOf(1,2,9)
try{
println(array[3])
}catch (e:IndexOutOfBoundsException){
e.printStackTrace()
}catch (e:Exception){
e.printStackTrace()
}