1、基本数据类型
类型 | 字节数 |
---|---|
Boolean | 1byte |
byte | 1byte |
Char | 2byte |
Short | 2byte |
Int | 4byte |
Float | 4byte |
Long | 8byte |
Double | 8byte |
2、变量
//可变变量
var a:Int = 10
a=20
//不可变变量
val b:Int=10
//普通字符串
val place = "吉林省长春市"
//原样输出字符串
val places = """
|吉林省
|长春市
""".trimMargin()
println(places)
函数式编程 : 函数可独立于对象 单独存在 这样的函数叫做 顶层函数 顶层函数内可以定义函数 叫嵌套函数
字符串模板:
val place1 = "天坛公园"
val str2 = "今天来到${place1},首先映入眼帘的是$place1 的${place1.length}个大字"
if else 语句
//kotlin 没有三元运算符
fun max(a:Int,b:Int):Int{
if(a > b){
return a
}else {
return b
}
}
//if语句精简版 kotlin 的if语句是有返回值的 函数式编程思想 声明式 和 表达式 函数思想 区别
fun max1(a:Int,b:Int):Int{
return if(a > b) a else b
}
class Girl{
//operator 用来重新定义运算符
operator fun plus(girl:Girl):Int{
return this.age+girl.age
}
val name = "小明"
var age = 20
}
val girl1 = Girl()
val girl2 = Girl()
girl2.age = 30;
val age = girl1+girl2
println(age)
多重循环的标签出返回
//多重循环的标签出返回
val str4 = "abc"
val str5 = "efg"
tag1@for (c1 in str4){
tag2@for (c2 in str5){
if(c1 == 'b' && c2 =='f'){
//此时只用break只会跳出里层循环 外层循环还会执行
break@tag1
}
}
}
//when 表达式 分支支持区间 条件语句都可以支持
fun todo(age:Int):String{
when(age){
is Int->{
return ""
}
1,2,3,4,5,6 ->{
return ""
}
in 1..6 -> {
return ""
}else->{
return ""
}
}
return ""
}
//不带参数的when语句
fun todo1(age:Int):String{
when{
age is Int->{
return ""
}
age == 6 ->{
return ""
}
age in 1..6 -> {
return ""
}else->{
return ""
}
}
return ""
}
//when表达式的返回值 返回值为分支大括号里的最后一行
fun todo2(age:Int):String{
return when{
age is Int->{
""
}
age == 6 ->{
""
}
age in 1..6 -> {
""
}else->{
""
}
}
return ""
}
函数表达式: 函数体只有一行时
获取函数引用:
匿名函数:
默认参数:
可变参数:
4、异常
异常处理:
编译时异常 :指的是某些函数抛出了异常,在我们调用时必须捕获或抛出去 必须处理
运行时异常 :指的是运行时发生的异常,编译期无法发现
kotlin不检查编译时 异常
5、面向对象
kotlin 会自动加入set 和 get方法
//自动生成get set方法 字段私有
val person = Person()
println(person.name)
//set方法不可见 加上private set
class Person{
var name:String = "李四"
//set方法的可见性 加上private set
//name 的set方法变为私有 外界无法访问
private set
var age:Int = 20
}
//修改或重写set方法
class Person{
var name:String = "李四"
//访问器的可见性 加上private set
//name 的set方法变为私有 外界无法访问
private set
var age:Int = 20
//重写set方法 利用field来代替age修改值 否则会递归调用set方法
set(value) {
if(value < 150 ) field = value else field = 150
}
}
//构造函数参数在类上直接填充
//init函数 充当了构造方法块
class Person1(name:String,age:Int){
var name:String = ""
var age:Int = 0
//构造函数里的代码都可以放到init中
init {
this.name = name
this.age = age
}
}
//构造函数简化 构造参数加var 或 val 则自动创建填充
//加上var后,自动创建name和age属性,并通过参数赋值
class Person2(var name:String,var age:Int){
}
//次构函数 用来重载构造函数 :冒号用来调用主构函数
class Person2(var name:String,var age:Int){
var phone:String = ""
//次构函数调用主构函数
constructor(name:String,age:Int,phone:String):this(name,age){
this.phone = phone
}
constructor(name:String,age:Int,phone:String,address:String):this(name,age){
}
}
类继承:
var son = Son()
println(son.name)
println(son.age)
son.honbe()
冒号 代表 继承
class Son:Father(){
fun tt(){
println(name)
}
override fun honbe() {
super.honbe()
}
}
//能够被继承 必须加上open关键字
open class Father(){
//属性继承
open var name:String = ""
open var age:Int = 20
//方法继承
open fun honbe(){
}
}
接口实现:
//类反应事物的本质 接口反应事物的能力
var xiaoming = Xiaoming()
xiaoming.no_id
xiaoming.drive()
xiaoming.ride()
xiaoming.run()
class Xiaoming:Human(),RideBike,driveCar{
//接口属性实现
override var no_id: String = ""
//接口方法实现
override fun drive() {
println("小明学会开车")
}
//接口方法实现
override fun ride() {
println("小明学会骑自行车")
}
}
open class Human{
}
interface driveCar{
//接口里定义属性
var no_id:String
//接口里定义方法
fun drive()
//接口里也可以实现方法
fun run(){
println("接口里定义的方法 直接实现 实现类里可以不实现该方法")
}
}
interface RideBike{
fun ride()
}
kotlin 类型强制转换
class Dog:Anima(){
fun sound(){
println("")
}
}
abstract class Anima{
}
var anima:Anima = Dog()
//通过 as 关键字 强制转换
val ani:Dog = anima as Dog
ani.sound()
// 通过 is 关键字 判断是否可以强转
//判断成功后 可不需要 as 强转 即可使用
if(anima is Dog){
anima.sound()
}
嵌套类 和 内部类
//inclass 为静态类 可通过outclass直接点出来创建
//静态类 与 外部无关 数据无法互通 java是可以互通的
//inner 关键字可以改变内部类为 非静态
//
var inClass = outClass().inclass()
class outClass{
var name:String=""
//嵌套类 属于 静态类 无法访问外部非静态属性
// inner关键字 可以改变内部类为 非静态
//通过this关键字访问内部或者外部属性
inner class inclass{
var name:String = ""
fun say(){
println("你好${this.name}")
println("你好${[email protected]}")
}
}
}
泛型:
//定义抽象泛型箱子类 此类包含一个有参构造方法
open abstract class Box<T>(var thing:T)
//定义箱子类的子类 该子类必须重载该有参构造方法 并且调用父类有参构造方法 且传入参数 同时明确其泛型类型
class FruitBox(thing:Fruit):Box<Fruit>(thing)
//定义箱子类的子类 重载并调用了父类构造方法,子类不明确父类泛型类型时 向父类传递子类泛型
class SomeBox<Q>(thing:Q):Box<Q>(thing)
//泛型上限 Q只能是Fruit子类
class MuchBox<Q:Fruit>(thing:Q):Box<Q>(thing)
//定义抽象水果类
open abstract class Fruit
//定义水果类的子类
class apple:Fruit()
//定义水果类的子类
class orange:Fruit()
//泛型投射 out 关键字允许传入Fruit的子类的list 否则不允许 (java中是允许的)
//out相当于java中的 (? extends Fruit)
fun setFruitList(list:ArrayList<out Fruit>){
println(list.size)
}
//in 关键字允许传入Fruit的父类 list
// in 相当于java中的(? super Fruit)
fun setFruitList(list:ArrayList<in Fruit>){
println(list.size)
}
//如果没有out关键字 不允许传入apple list 只能传入 Fruit list
var array = ArrayList<apple>()
setFruitList(array)
//星号* 投射
//* 表示 可以传入任意类型的list集合
// * 相当于java中的 ?
fun setFruitList(list:ArrayList<*>){
println(list.size)
}
//泛型函数
//泛型函数 先定义泛型 再使用泛型
fun <T> pabType(thing:T){
when(thing){
is Int->{
println("")
}
is String->{
println("")
}
else->{
println("")
}
}
}
//获取泛型类型
inline fun <reified T> fan(thing:T){
//获取泛型类型 加 (java里需要通过反射来获取,因为运行期泛型会擦除)
println(T::class.java.name)
}
中缀表达式:
中缀表达式使用条件
1、必须是成员函数或扩展函数(非顶层函数)
2、当前函数必须只有一个参数
3、参数不能是可变参数或默认参数
class person{
//infix 关键字
infix fun sayHello(name:String){
println("hello$name")
}
}
val per = person()
per.sayHello("xiaoming")
//中缀表达式
per sayHello "xiaoming"
//infix 还可以自定义一些操作符 例如二元组
//这里的 to 就是infix 自定义的操作符
val pair2 = Pair<String,Int>("小明",20)
val pair3 = "小明" to 20
委托模式:
接口委托
//定义接口能力
interface WashPower{
fun wash()
}
//实现接口能力
class BigSon:WashPower{
override fun wash() {
}
}
//委托接口能力
class SmallFather:WashPower by BigSon(){
}
//委托接口能力 动态委托 将委托人传入构造函数
class SmallFather1(washPower: WashPower):WashPower by washPower{
}
//委托接口能力 能力加强
class SmallFather2(var washPower: WashPower):WashPower by washPower{
override fun wash() {
println("加强委托能力")
washPower.wash()
}
}
属性委托
//将Son1的money 的 get set 方法委托给Mother
class Son1{
var money:Int by Mother()
}
class Mother{
operator fun getValue(son1: Son1, property: KProperty<*>): Int {
return money
}
operator fun setValue(son1: Son1, property: KProperty<*>, i: Int) {
money+=i
}
var money:Int = 0
}
惰性加载和延迟加载:
class Person3{
//类创建加载时 name 属性就会加载并初始化
val name:String = ""
//优化 使用该属性的时候再加载 惰性加载
//必须使用val 不可变
//by lazy 的返回值是 最后一行
//by lazy 属于线程安全 同步块
val name1:String by lazy { "张三" }
//lateinit关键字 延迟加载 没有初始值 必须使用var 以后忘记赋值 运行会抛异常 通过异常准确定位错误
lateinit var name2:String
fun setName2(){
name2 = "张三"
}
}
扩展函数:
扩展函数是 不改变类的情况下添加函数
扩展String 类:
//当前String 不可为空
fun String.myStringIsEmpty():Boolean{
return this.length == 0
}
//当前String 可以为空 当String为null时 返回true
fun String?.myStringIsEmpty1():Boolean{
//this 可访问当前类或当前类属性
return this==null || this.length == 0
}
var name:String? = null
//name做非空判断 如果为null 返回null
val flag:Boolean? = name?.myStringIsEmpty()
//name不做非空判断 因为myStringIsEmpty1可传null 传null时返回true
val flag1:Boolean = name.myStringIsEmpty1()
子类调用父类扩展函数:
//定义父类
open class Father1
//定义子类
class Son2:Father1()
//扩展父类函数
fun Father1.sayhello(){
println("")
}
//子类调用父类扩展函数
val son3 = Son2()
son3.sayhello()
kotlin单例模式:
//object关键字将类utils变为 单例模式
//此单例模式下 类的所有属性为static静态类型
//所以object单例模式 只适用于 属性较少的类 否则会浪费资源
object utils{
val name:String = ""
fun sayHello(){
println("")
}
}
//自定义 单例模式
//1、将该类构造函数变为私有 通过 private constructor关键字
//2、通过伴生对象companion object关键字定义静态属性instance
//3、通过懒加载初始化instance 懒加载确保instance只初始化一次 且线程安全
class Person4 private constructor(){
var name:String = ""
//伴生对象companion object块内的属性为静态static
companion object{
var age:Int = 20
val instance:Person4 by lazy { Person4() }
}
}
//单例调用
Person4.instance.name
枚举类:
//enum 关键字定义枚举
enum class Color(var r:Int,var g:Int,var b:Int){
RED(255,0,0),BLUE(0,255,0),GREEN(0,0,255)
}
//枚举调用
Color.BLUE.r
数据类:
data关键字为该类 实现了
1、构造方法
2、get set方法
3、toString方法
4、equces方法
5、copy方法
6、hashcode方法
7、component方法 (component1返回第一个元素 component2返回第二个元素)
data class News(var name:String,var title:String,var content:String)
var news = News("名称","标题","内容")
news.name
news.component1()
news.component2()
val(namess,title,content) = News("名称","标题","内容")
println(namess)
密封类:
关键字 sealed 代替 open
父类为密封类 子类可以封装进父类
超强的枚举
//定义密封父类 其中两个子类在密封类内 一个子类在密封类外
sealed class NedStack{
class Ned1:NedStack(){}
class Ned2:NedStack(){}
}
class Ned3:NedStack(){}
//利用密封类判断子类类型
fun hasRight(nedStack: NedStack):Boolean{
return when(nedStack){
is NedStack.Ned1->true
is NedStack.Ned2->true
else -> false
}
}
集合:
list集合
// listof 生成只读集合 不能添加 不能修改
val list = listOf("","")
//mutableListOf生成的集合 为可变集合 可添加 可修改
val list1 = mutableListOf("","")
//创建java list集合
val list2 = arrayListOf("","")
val list3 = ArrayList<String>()
//集合过滤
//找到集合里的某个元素
val l1 = list.find {it:String ->
it.startsWith("张")
}
//过滤得到包含返回为true的元素的一个新集合
val l2 = list.filter {it:String ->
it.startsWith("张")
}
//把一个集合过滤出的元素添加到另外一个集合中
list.filterTo(list1,{it:String ->
it.startsWith("张")
})
//把一个集合中下标为偶数的元素过滤出来
val l3 = list.filterIndexed { index:Int, s:String ->
index%2 == 0
}
//集合排序
class Person2(var name:String,var age:Int)
//list存储基本类型或String 直接排
list.sorted() //正序
list.sortedDescending() //倒叙
//list存储引用类型,按引用类型的字段排
val list4 = listOf<Person2>(Person2("",10))
//按照Person2的age字段正序排列
list4.sortedBy { it:Person2->
it.age
}
//按照Person2的age字段倒叙排列
list4.sortedByDescending {it:Person2->
it.age
}
//最值
list.max()
list.min()
list4.maxBy {it:Person2->
it.age
}
list4.minBy { it:Person2->
it.age
}
//分组
//张姓一组 李姓一组 其他一组
val map:Map<String,List<String>> = list.groupBy {it:String->
when(it.substring(0,1)){
"张"->"张"
"李"->"李"
else ->"其他"
}
}
//去重复
list.toSet() //变成set集合 去重复
//基本类型或String直接去重
list.distinct()
//引用类型 去重Person2 名字相同的对象
list4.distinctBy {it:Person2->
it.name
}
//去重 同姓
list4.distinctBy {it:Person2->
it.name.substring(0,1)
}
//集合拆分 拆成一个二元组
val pair4:Pair<List<String>,List<String>> = list.partition { it:String->
it.startsWith("张")
}
//集合map函数 处理集合数据 返回新集合
//取该集合元素的每一个首字母
val list5:List<String> = list.map { it:String->
it.substring(0,1)
}
//集合相加
//把集合元素某个属性相加结果 返回
val allAge:Int = list4.sumBy { it:Person2->
it.age
}
set集合 元素不可重复
// setOf 生成只读集合 不能添加 不能修改
val set = setOf("","")
//mutableSetOf生成的集合 为可变集合 可添加 可修改 不可重复
val set1 = mutableSetOf<String>()
//创建java set集合 TreeSet 顺序集合
val set2 = TreeSet<String>()
map 集合
// mapOf 生成只读集合 不能添加 不能修改
val map1 = mapOf<String,Int>()
val map2 = mapOf(1 to "",2 to "")
//mutableMapOf 生成的集合 为可变集合 可添加 可修改
val map3 = mutableMapOf(1 to "",2 to "")
//创建java map 集合
val map4 = HashMap<Int,String>()
函数式编程:
函数式编程就是 函数可以作为方法的返回值,也可以作为方法的参数
函数和类都是一等公民 没有线程安全问题 高并发比较适用 但是不能完全代替面向对象编程
函数是 不保存状态的 执行完即销毁 调用多少次 如下打印出来的都是10
fun test(){
var a = 10
println(a)
a++
}
闭包可以让函数保存状态
闭包:一个函数返回了一个内部函数,该内部函数引用了外部函数的相关参数和变量,我们把该返回的内部函数成为闭包
kotlin中的闭包就是lambda表达式
fun test1():()->Unit{
var a = 10
return {
println(a)
a++
}
}
高阶函数:就是 某个函数将函数作为参数传递
如下 定义了两个函数add1和sub 以及一个 高阶函数cacl
//将函数作为参数
//a:第一个参数 b:第二个参数 c:函数(包括参数和返回值) 最后返回Int
fun cacl(a: Int,b: Int,c:(Int,Int)->Int):Int{
return c.invoke(a,b)
}
fun add1(a:Int,b:Int):Int{
return a+b
}
fun sub(a:Int,b:Int):Int{
return a-b
}
高阶函数的调用
函数作为参数时,要使用其引用类型
val a1 = 10
val b1 = 20
var sum = add1(a1,b1)
var sum1 = sub(a1,b1)
//传入函数的引用
var sum2 = cacl(a1,b1,::add1)
var sum3 = cacl(a1,b1,::sub)
lambda表达式 就是 匿名函数
var sum4 = cacl(a1,b1,{m,n->
m+n
})
var sum5 = cacl(a1,b1,{m,n->
m-n
})
//lambda表达式如果是最后一个参数,则可以写到括号外
var sum6 = cacl(a1,b1){m,n->
m-n
}
//匿名函数(lambda)的定义及使用
//使用()调用
{
println("")
}()
//使用invoke调用
{
println("")
}.invoke()
//带参数及返回值的匿名函数(lambda)
{
a:Int,b:Int->
a+b
}(10,20)
//接收匿名函数(lambda)的返回值
val result = {
a:Int,b:Int->
a+b
}(10,20)
//匿名函数(lambda)的引用
val foo:(a:Int,b:Int)->Int ={
a:Int,b:Int->
a+b
}
foo(10,20)
foo.invoke(10,20)
val fo:()->Unit = {
println("")
}
fo()
fo.invoke()
//可空的匿名函数(lambda)的引用
val fooo:((a:Int,b:Int)->Int)? ={
a:Int,b:Int->
a+b
}
//匿名函数(lambda)中 it的使用
//定义一个高阶函数 第一个参数为Int类型,第二个参数为函数类型(该函数的参数为int类型,返回值为int类型),返回值为int类型
fun haha(a:Int,b:(c:Int)->Int):Int{
return b(a)
}
//调用这个高阶函数 lambda表达式只有一个参数时 默认用it来表示
val mm = haha(10){
it+10
}
val mn = haha(10){a->
a+10
}
println("===========================$mm")
println("===========================$mn")
//lambda表达式的返回值
//lambda表达式的返回值是 函数的最后一行 不需要return语句
四大表达式
Apply 大范围的控制处理
//1、apply是所有类型的扩展函数 任意类型都有Apply函数扩展 Apply参数是一个调用者的函数
class Datas{
var name = ""
fun da(){
println("")
}
}
fun set(block:()->Unit){
block()
}
fun set1(block:Datas.()->Unit){
Datas().block()
block(Datas())
}
set{
}
set1 {
name = ""
da()
}
//2、apply的参数是一个调用者的扩展函数T.()->Unit
//3、lambda表达式里this代表调用者
//4、在lambda表达式里可以访问调用者的方法
//5、apply函数的返回值就是 调用者本身
list1?.apply {
add("")
this.set(0,"")
val v = this.get(0)
}?.add("")
Let
//1、let是所有类型的扩展函数 任意对象都有let扩展函数
//2、let参数也是一个函数 该函数参数是let的调用者本身
//3、let函数的返回值 就是他参数函数的返回值 也就是lambda表达式的返回值(lambda表达式的最后一行)
list1.let {
it.add("")
""
}.length
With
//1、with是一个独立的函数 任意地方可以调用
//2、with函数需要接收两个函数 第一个参数任意类型a 第二个参数是a的扩展函数,该函数返回值就是with函数的返回值
//3、with函数的返回值 是第二个参数的返回值
with(list1,{
this.add("")
""
}).length
//括号前移
with(list1){
this.add("")
""
}.length
Run
//1、run是所有类型的扩展函数 任意类型都有run扩展函数
//2、run函数参数是调用者的扩展函数 该函数的返回值 就是run函数的返回值
//3、run函数的返回值就是其参数的返回值
list1.run {
this.add("")
""
}.length
函数回调
//处理对象
class Oyi(val name:String){}
//处理对象工具类
class boy{
fun findOyi():Oyi{
val oyi = Oyi("海天")
return oyi
}
}
//定义函数回调
class superMa(){
fun getOyi(f:(boy)->Unit){
Thread{
Thread.sleep(2000)
val b = boy()
f(b)
}.start()
}
}
val superma = superMa()
//执行函数回调
superma.getOyi {
val oyi = it.findOyi()
}