前言Kotlin学习笔记
1.val和var区别2.简单变量之间的转换3.数组变量的声明4.字符串
字符串与基本类型的转换字符串常用方法字符串模板及其拼接 5.容器
集合Set/MutableSet队列List/MutableList映射Map/MutableMap 6.条件分支语句
简单分支多路分支 7.循环处理
循环遍历跳出多重循环 8.空安全
字符串的有效性判断声明可空变量检验空值的运算符 9.等式判断
结构相等引用相等is 和 in 10.函数
与Java声明方式的区别输入参数的格式输出参数的格式默认参数可变参数几种特殊的函数泛型函数内联函数(没怎么理解)简化函数尾递归函数高阶函数lambda函数 11.增强系统函数
扩展函数扩展高阶函数日期函数单例对象 12.类和对象
类的构造类的构造函数带默认参数的构造方法类的成员
成员变量成员方法 伴生对象静态属性类的继承
开放性修饰符普通类的继承抽象类接口接口代理 小结几种特殊的类
嵌套类内部类枚举类密封类(没太懂)数据类模板类
前言由于在自己面试过程中,经常被问到有没有学过kotlin,总感觉自己少了点东西,于是就花了一个多星期将最基本的kotlin知识点给学了一遍,本篇文章仅仅含有一点点Android的知识,并不是学习Android的好文章,但是是最快入门kotlin的一篇全面的文章,当然,我也希望大家与我共同学习进步,如果有什么疑问,或者经验交流,都可以加群QQ:1098392728与我们交流。
更多好文章可以去浏览我的个人博客WilliamTao的博客
2.简单变量之间的转换val 可以理解为java中的final关键字,只能在声明的时候赋值
var 在任何时候都可以赋值
//Float --->Int
val orgin:Float = 65.0f
print(orgin.toInt())
3.数组变量的声明
kotlin中没有Stringarray,而是使用Array ,具体看下面的例子
fun main() {
var int_arrary:IntArray = intArrayOf(1,2,3)
print(int_arrary)
var string_array:Array=arrayListOf("hello","world")
}
其实,上面图片的内容都可以不用,直接使用Array 《》括起来就可以了
数组的获取,可以通过java的中括号,也可以使用get来获取
var string_array:Array=arrayOf("hello","world") Btn_test.setOnClickListener{ var str :String="" var i:Int = 0 while(i 4.字符串 字符串与基本类型的转换 kotlin方便一点,便于记忆
var test:String="1" println(test.toInt())字符串常用方法indexOfsubstringsplit:在Java里返回的是String[],而在kotlin中返回的是List通过下标获取某个位置的字符
var orgin:String ="he.llo.wor.ld" var list:List=orgin.split(".") for(item in list){ print("----"+item+"*----") } var orgin:String ="hello,world" var orgin_trim:String=orgin if(orgin_trim.indexOf(",")>0){ orgin_trim = orgin_trim.substring(0,orgin_trim.indexOf(",")) } println("orgin_trim--"+orgin_trim)println(orgin[1].toString()) println(orgin.get(1).toString())字符串模板及其拼接$加变量,如果变量先需要进行计算,则需要加大括号
var name="William_Tao" print("My name is $name ,and age is ${name.length}")5.容器Set
List
Map
公共方法
集合Set/MutableSetkotlin允许对容器进行初始化,而java不可以
循环的方法:for迭代器
//方法一 var setList: Set= setOf("test", "second", "thrid") for (item in setList) { println("名称: $item") } //方法二 var iterator = setList.iterator() while(iterator.hasNext()){ val item=iterator.next() println("名称: $item") } //方法三 setList.forEach { println("名称: $it") } 队列List/MutableList缺点所在:
var ListList: List= listOf("test", "second", "thrid") for (i in ListList.indices) { var item =ListList[i] println("名称: $item") } list中还提供了两种排序的函数 分别为:
sortBysortedByDescending
ListList.sortedBy { it.length } // ListList.sortedByDescending { it.length } for (i in ListList.indices) { var item =ListList[i] println("名称: $item") }映射Map/MutableMap两种初始化的方法:
键值 to 键名
Pair(值 ,名)
var godMap:Map= mapOf("苹果" to "Iphone 12","Android" to "VIVO") var godMap2:MutableMap = mutableMapOf(Pair("苹果" , "Iphone 12"), Pair("Android" , "VIVO")) 遍历(同前面那有三种一样,不过有点点区别),见下方
foreach需要 API 24 版本以上才行
//1 for(item in godMap){ println("键名:${item.key}键值:${item.value}") } //2 var iterator=godMap.iterator() while(iterator.hasNext()){ var item = iterator.next() println("键名:${item.key}键值:${item.value}") } //3 godMap.forEach { key, value -> "键名:${key}键值:${value}"}6.条件分支语句 简单分支在kotlin中,对分支语句做了优化,
允许分支语句返回字符串
另外,kotlin没有三元运算
//方法一 var flag:Boolean=false Btn_test.setOnClickListener { textView.text = if(flag==true){"flag is true" }else { "flag is false" } flag = !flag } //方法二,再一的基础上去掉{} var flag:Boolean=false Btn_test.setOnClickListener { textView.text = if(flag==true)"flag is true" else "flag is false" flag = !flag }多路分支注意与switch case之间的区别
when 替代了 switch数值 -> 代替了caseelse替代了defaultkotlin中每一个 分支自动跳出when -> 同样允许有返回值在java中case后面只能引入常量,但是kotlin允许引入变量判断。在java中case后面只能引入一个常量,如果有多个常量的话,就需要并列写多个,很麻烦,在kotlin中就对此进行了优化,具体见代码kotlin中的when ->也支持类型判断(is 变量类型)
//版本一 var count:Int =0; Btn_test.setOnClickListener { when(count){ 0 -> textView.text="你现在的数值为:0" 1 -> textView.text="你现在的数值为:1" // else -> textView.text="你现在的数值为:default" } count = (count+1)%3 } //最简化版本 var count:Int =0; Btn_test.setOnClickListener { textView.text= when(count){ 0 -> "你现在的数值为:0" 1 -> "你现在的数值为:1" else -> "你现在的数值为:default" } count = (count+1)%3 }//引入变量可以通过 var count:Int=0 var one:Int =1 var tow:Int =2 Btn_test.setOnClickListener { when(count){ one -> textView.text="你现在的数值为:0" tow -> textView.text="你现在的数值为:1" // else -> textView.text="你现在的数值为:default" } count = (count+1)%3 }koltin对于多个常量并列的优化
var count:Int=0 Btn_test.setOnClickListener { when(count){ 1,3,5,7,9 -> textView.text="你现在的数值为:1,3,5,7,9当中的某个值" in 10..15 -> textView.text="你现在的数值为:10..15当中的某个值" else -> textView.text="你现在的数值为:default" } count = (count+1)%20 }kotlin中的when ->也支持类型判断(is 变量类型)
var countType:Number; var countNumb:Int=0 Btn_test.setOnClickListener { countNumb = (countNumb+1)%3 countType = when(countNumb){ 0->countNumb.toLong() 1->countNumb.toFloat() else ->countNumb.toDouble() } //when ->使用类型的判断 textView.text=when(countType){ //重点关注此段 is Long ->"is long" is Float ->"is Float" is Double ->"is Double" else -> "is error" } }7.循环处理 循环遍历kotlin废除了for( int i=0;i
变量 in …for(i in 容器.indices)
//方法一 var list:Array= arrayOf ("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山") Btn_test.setOnClickListener { var poem:String="" for(item in list){ poem = "$poem$item,n " } textView.text = poem } //方法二 var list:Array = arrayOf ("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山") Btn_test.setOnClickListener { var poem:String="" for(i in list.indices){ if(i%2==0){ poem = "$poem${list[i]},n " }else{ poem = "$poem${list[i]}。n " } } textView.text = poem } 方法二所带来的问题
解决办法
kotlin引入了一些关键字,具体见下面代码(当然是用Java中的while,do —while都行)
//左闭右开,不包括2 16 ---65 for(i in 16 until 66){ println(i) } println("**********") //每一步走4 for(i in 23..89 step 4){ println(i) } println("**********") //从50开始递减到7 for(i in 50 downTo 7){ println(i) } //使用while var list:Array= arrayOf ("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山") var i:Int=0 while(i 跳出多重循环 低配版本
//这里有空语句所以注意时Array而非Array var list:Array = arrayOf("朝辞白帝彩云间",null,"千里江陵一日还",""," ","两岸猿声啼不住","轻舟已过万重山") Btn_test.setOnClickListener { var poem:String="" var pos:Int=-1 var count:Int=0 while(pos<=list.size){ pos++; //判断是否为空或者是否是有空串或者空格串 if(list[pos].isNullOrBlank()){ continue } if(pos%2==0){ poem = "$poem${list[pos]},n " }else{ poem = "$poem${list[pos]}。n " } count++ //若合法行数达到4行,则跳出循环 if(count==4){ break } } textView.text = poem } 高配版 outside@
//这里有空语句所以注意时Array而非Array var list:Array = arrayOf("朝辞白帝彩云间",null,"千里江陵一日还",""," ","两岸猿声啼不住","轻舟已过万重山") Btn_test.setOnClickListener { var i:Int=0 var is_found =false //给外循环加一个名叫outside的标记 outside@ while (i 8.空安全 字符串的有效性判断 声明可空变量 正常默认的变量都是非空的
可以为空的变量,可以在声明前在类型后面加问号
//能调用上面6中方法中的任意一个 var strNotNull:String="" //只能调用 isNullOrEmpty 和 isNullOrBlank方法,因为其与方法需要求其长度,但可能为空,所以不可以调用后面4种方法 var strCanNull:String?=null检验空值的运算符var length_null:Int? var A:String="123" Btn_test.setOnClickListener { //表示为空时返回null,所以返回的变量必须被声明为可空类型 length_null = A?.length //length_null = A?.length?:-1 //length_null = A!!.length } textView.text = length_null.toString()9.等式判断 结构相等凡是在Java中实现了equals函数的类,其变量均可在Kotlin中通过运算符“==”和“!=”进行等式判断
这种比较变量结构内部值的行为,kotlin称为结构相等,即模样相等
var helloHe:String="你好" var helloShe:String="哈喽" var flag:Boolean=false var resultCont:Boolean=false Btn_test.setOnClickListener { titile.text = "$helloHe 与$helloShe 的对比结果为:" if(flag){ resultCont=helloHe==helloShe content.text = "最后的对比结果为:$resultCont" }else{ resultCont=helloHe!=helloShe content.text = "最后的对比结果为:$resultCont" } flag=!flag }引用相等kotlin中 引用相等用 =,引用不等用!
但是在绝大多数场合,结构相等和引用相等的判断结果是一致的,
var time:Date = Date() var timeCopy:Any = time.clone(); var count:Int=0 Btn_test.setOnClickListener { when(count++%4){ 0 ->{titile.text="比较time 和timeCopy是否结构相等" ;content.text="==比较的结果为${time==timeCopy}"} 1 ->{titile.text="比较time 和timeCopy是否结构不相等";content.text="!=比较的结果为${time!=timeCopy}"} 2 ->{titile.text="比较time 和timeCopy是否引用相等";content.text="!=比较的结果为${time===timeCopy}"} 3 ->{titile.text="比较time 和timeCopy是否引用不相等";content.text="!=比较的结果为${time!==timeCopy}"} } }is 和 in前两者提到的等式判断其实比较的是变量,当然,还有一些操作,比如判断一个变量的类型,判断一个数组是否包含某一个数,那么这时就需要用到下面的方法啦
is
!is
具体写法:变量名 is(!is) 类型名称
var A:Double=53.3 print(A is Double) var B:Double=53.3 print(B !is Double)在java中如何判断一个数是否在数组中,需要通过循环来实现,而在kotlin中通过in 、!in来实现
var oneArray:IntArray = intArrayOf(1,2,3) var four:Int=4 var one:Int=1; print("four is in or not in: ${four in oneArray}") print("four is in or not in: ${one in oneArray}")10.函数 与Java声明方式的区别输入参数的格式
//不带参数的 fun function1(){ tv.text="123"; } //带参数的 fun function2(str:String){ tv.text="123$str" } //可带空的参数的 fun function3(str:String?,num:Int){ tv.text=if(str==null){"123"}else{"123$str"} } //调用函数的方法 btn.setOnClickListener{function1();function2("123");function3(null,5)}输出参数的格式//不带参数的 fun function1():Unit{ tv.text="123"; } //带参数的 带返回值的 fun function2(str:String):String{ return "$str"; } //带输入和输出的 fun function3(str:String?,num:Int):String{ tv.text=if(str==null){"123"}else{"123$str"} return "success"; } //调用方法同上一样,没区别默认参数fun function2(str:String="指南针"):String{ return "$str"; }可变参数vararg 表示其后的参数个数是不确定的
//可变数组为string类型 fun getData(general:String,first:String="first",vararg otherArray:String?):String{ var answer="$general,$first," for(item in otherArray){ answer="$answer,$item" } return answer } //调用实例 btn.setOnClickListener{getData("general","first","second","third");}//可变数组类型为数组类型(相当于两层的数组) //可变数组为string类型 fun getData(general:String,first:String="first",vararg otherArray:Array几种特殊的函数){ var answer="$general,$first," for(array in otherArray){ for(item in array){ answer="$answer,$item" } } return answer } //调用实例 btn.setOnClickListener{getData("general","first",arrayOf("1","2","3"),arrayOf("4","5","6"));} 泛型函数1.泛型函数
funappendString(tag:String,vararg otherInfo:T?):String{ var str:String="$tag" for(item in otherInfo){ str="$str${item.toString()}" } return str } var count=0 when(count++%3){ 0-> appendString内联函数(没怎么理解) 简化函数("古代四代发明","造纸术","硬刷术","火药","指南针") 1-> appendString ("古代四代发明",1,2,3); else -> appendString ("古代四代发明",5.5,5.6,5.7) } Kotlin把函数当做一种特殊变量
//常规写法 fun fac(n:Int):Int{ if(n<=1) n else n*fac(n-1) }//简化写法 fun fac(n:Int):Int= if(n<=1) n else n*fac(n-1)尾递归函数1函数末尾的返回值重复调用自身函数
2.关键字tailrec
3.使用tailrec编译器会相对应的进行优化(采用循环方式代替递归,从而避免了栈溢出的情况)
tailrec fun findFixPoint(x:Double=1.0):Double=if(x==Math.cos(x))x else findFixPoint(Math.cos(x))高阶函数1
var str_array:Arraylambda函数= arrayOf("Hello","world",", ","I'm "); println("系统默认的最大值比较结果为${str_array.maxOrNull()}") print("系统默认的最大值比较结果为(高阶函数实现)${maxCoustom(str_array,{a,b->a>b})}") print("按照长度比较 ${maxCoustom(str_array,{a,b->a.length>b.length})}") print("按照去除空格之后的长度比较 ${maxCoustom(str_array,{a,b->a.trim().length>b.trim().length})}") 看前面的有个,{a,b->a.length>b.length},这个就是lambda函数
前一部分是输入参数,后面一部分是函数体
//完整写法 fun anonymous(a:String,b:String):Boolean{ var result:Boolean = a.length>b.length return result }11.增强系统函数 扩展函数扩展高阶函数
日期函数.
单例对象.
12.类和对象 类的构造
//类的构造 class easyClass { init { println("类的初始化") } } //实例化 var test:easyClass = easyClass() var test1 = easyClass()类的构造函数class easyClass constructor(context:Context,name:String){ init { println("${name}类的初始化 ") } }为了让类有多个携带不同参数的构造方法,kotlin引入了主构造函数和二级构造函数,具体见下面的代码
跟在类后面的参数是主构造函数的入参;
二级构造函数可以在内部直接书写完整的函数表达式;
class easyClass constructor(context:Context,name:String){ init { println("${name}类的初始化 ") } constructor(context:Context,name:String,sex:Int):this(context,name){ var sexName =if(sex==0) "公" else "母" println("这是一只名叫${name} 是${sexName}的") } }补充说明:
二级构造函数和普通函数的区别:
上面代码有个问题就是他首先先会执行主构造函数,然后调用二级构造函数,有时候我们并不想让他执行主构造,这时就可以参考如下:把几个构造方法都放在类的内部定义
class easyClass { constructor(context:Context,name:String){ println("${name}类的初始化 ") } constructor(context:Context,name:String,sex:Int):this(context,name){ var sexName =if(sex==0) "公" else "母" println("这是一只名叫${name} 是${sexName}的") } }带默认参数的构造方法//类的柱构造方法使用了默认参数 class easyClass constructor(context:Context,name:String,sex: Int=0) { init { var sexName =if(sex==0) "公" else "母" println("这是一只名叫${name} 是${sexName}的") } } 实例化 //传入两个参数 var test:easyClass = easyClass(context,"狗") //传入是三个参数 var test1 = easyClass(context,"狗",20)为了解决java和kotlin在默认参数定义上的不同,引入了@JvmOverloads,告知编译器这个类是给java重载用的(好比配备了一个同声翻译机,能听得懂Kotlin,也能听得懂Java)
加入@JvmOverloads目的就是让java代码也能识别默认参数
//类的柱构造方法使用了默认参数,引入了 @JvmOverloads class easyClass @JvmOverloads constructor(context:Context, name:String, sex: Int=0) { init { var sexName =if(sex==0) "公" else "母" println("这是一只名叫${name} 是${sexName}的") } }类的成员 成员变量//之前写代码为成员变量赋值的方法习惯 class WildAnimal (name:String,Sex:Int=0){ var name:String val Sex:Int init { this.name=name this.Sex=Sex } } //增加了val(不可变) 和var(可变),通过kotlin某种机制让编译器自动对其成员变量命名的与赋值 class WildAnimal (var name:String,val Sex:Int=0){ }class WildAnimal (var name:String,val Sex:Int=0){ var SexName:String init { SexName=if(Sex==0)"公" else "母" } }成员方法class WildAnimal (var name:String,val Sex:Int=0){ var SexName:String init { SexName=if(Sex==0)"公" else "母" } fun getDes(tag:String):String{ return "欢迎来到${tag}:这只${name}是${SexName}" } } //外部调用 WildAnimal("猫",0).getDes("test")伴生对象//伴生对象 class WildAnimalCompanion (var name:String,val Sex:Int=0){ var SexName:String init { SexName=if(Sex==0)"公" else "母" } fun getDes(tag:String):String{ return "欢迎来到${tag}:这只${name}是${SexName}" } //companion 表示伴随 object表示对象 WildAnimal表示伴随对象的名称 companion object WildAnimal{ fun judgeSex(sexName:String):Int{ var sex:Int = when(sexName){ "公" ->0 "母" ->1 else->-1 } return sex } } } //外部调用----------等价于java中的静态方法调用 print( WildAnimalCompanion.judgeSex("母")) print(WildAnimalCompanion.WildAnimal.judgeSex("公"))静态属性静态属性,静态方法都是在伴生对象中去定义的
class WildAnimalCompanion (var name:String,val Sex:Int=0){ var SexName:String init { SexName=if(Sex==0)"公" else "母" } fun getDes(tag:String):String{ return "欢迎来到${tag}:这只${name}是${SexName}" } //companion 表示伴随 object表示对象 WildAnimal表示伴随对象的名称 companion object WildAnimal{ //静态常量的值是不可以变得,所以需要用val修饰 val MALE=1 val FEMALE=0 val UNKNOW=-1 fun judgeSex(sexName:String):Int{ var sex:Int = when(sexName){ "公" ->MALE "母" ->FEMALE else->-UNKNOW } return sex } } } //外部调用静态属性 WildAnimalCompanion.FEMALE类的继承 开放性修饰符//父类 open class Bird(name:String,sex:Int){ } //子类继承Bird class test(name:String,sex:Int) :Bird(name,sex) { }普通类的继承open class Bird(var name:String,val sex:Int){ var sexName:String //初始化 init { sexName=getSexName(sex) } //bird内部的一个方法 open protected fun getSexName(sex:Int):String{ return if(sex==MALE)"公" else "母" } //伴随对象,包含静态变量和静态方法 companion object BirdStatic{ val MALE=1 val FEMALE=0 val UNKNOW=-1 fun judgeSex(sexName:String):Int{ var sex:Int = when(sexName){ "公" ->MALE "母" ->FEMALE else->-UNKNOW } return sex } } }//父类Bird已经在构造函数声明了属性,故Duck无需重复声明属性 //也就是说,子类的构造方法在输入参数时,无需再加val和var class Duck(name:String="鸭子",sex:Int=Bird.MALE) :Bird(name,sex) { }子类重新定义新的成员属性和成员方法
class Ostrich(name:String="鸵鸟",sex:Int=Bird.MALE) :Bird(name,sex) { override fun getSexName(sex: Int): String { return if (sex== MALE) "雄" else "雌" } }抽象类抽象类以及接口中的方法,默认都是open(即是可以被继承的)
abstract class Chicken(name:String, sex:Int, var voice:String) : Bird(name, sex) { val numberArray:Array接口= arrayOf("1","2","3") //抽象方法必须在子类中重写 abstract fun callOut(times:Int):String } open class Bird(var name:String,val sex:Int){ var sexName:String //初始化 init { sexName=getSexName(sex) } //bird内部的一个方法 open protected fun getSexName(sex:Int):String{ return if(sex==MALE)"公" else "母" } //伴随对象,包含静态变量和静态方法 companion object BirdStatic{ val MALE=1 val FEMALE=0 val UNKNOW=-1 fun judgeSex(sexName:String):Int{ var sex:Int = when(sexName){ "公" ->MALE "母" ->FEMALE else->-UNKNOW } return sex } } }interface Behavior { //接口内部的方法默认就是抽象类,所以不加abstract也可以,当然open也可以不加 open abstract fun fly():String //接口内部的所有方法都默认open类型 fun swin():String //kotlin允许在接口实现方法 fun run():String{ return "和哈哈哈" } //kotlin的接口允许声明抽象属性,实现该接口的类必须重载该属性 // open abstract val skillSports:String val skillSports:String }class Goose(name:String="天鹅",sex:Int=Bird.FEMALE) : Bird(name,sex),Behavior { override fun fly(): String { TODO("Not yet implemented") return "fly" } override fun swin(): String { TODO("Not yet implemented") return "swin" } //因为接口已经实现该方法,所以在继承接口的时候此方法可以写也可以不写 override fun run(): String { return super.run() } //重载来自接口的抽象类 override val skillSports: String = "打篮球" }//外部调用下· Goose().fly() Goose().swin() Goose().skillSports接口代理通过关键字by表示该接口将由入参中的代理类实现、
interface Behavior { //接口内部的方法默认就是抽象类,所以不加abstract也可以,当然open也可以不加 open abstract fun fly():String //接口内部的所有方法都默认open类型 fun swin():String //kotlin允许在接口实现方法 fun run():String{ return "和哈哈哈" } //kotlin的接口允许声明抽象属性,实现该接口的类必须重载该属性 // open abstract val skillSports:String val skillSports:String }class BehaviorFly:Behavior { override fun fly(): String { return "翱翔天空" } override fun swin(): String { return "落水凤凰不如鸡" } override val skillSports: String="飞翔" }class BehaviorSwim:Behavior { override fun fly(): String { return "看情况,大雁能展翅高飞,企鹅却欲飞还休" } override fun swin(): String { return "怡然戏水" } override val skillSports: String="游泳" }class WildFowl(name:String,sex:Int=Bird.MALE,behavior: Behavior):Bird(name,sex),Behavior by behavior { } //外部调用 WildFowl("老鹰",Bird.MALE,BehaviorSwim())小结几种特殊的类 嵌套类调用嵌套类时,得在嵌套类得类名前添加外部类得类名,相当于把这个嵌套类作为外部类得静态对象使用。
//外部调用嵌套类 //由于嵌套类无法访问外部类得成员,所有七方法只能返回自身的信息 Tree.Flower("桃花")class Tree(treeName:String) { // 下面的类访问不到treeName class Flower(var flowerName:String){ return "$flowerName" } }内部类class Tree(treeName:String) {
枚举类
// 下面的内部类可以访问到treeName
inner class Flower(var flowerName:String){
return “$flowerName”
}
}enum class SeasonType { SPRING,SUMMER,AUTUMN,WINTER }enum class SeasonName(val seasonName: String) { SPRING("春天 "), SUMMER("夏天"), AUTUMN("秋天"), WINTER("冬天") } //ordinal 代表枚举类得序号,name代表枚举类得名称 //使用自定义的seasonName代表更个性化的叙述 print(SeasonName.SPRING.ordinal ) println(SeasonName.SPRING.seasonName)密封类(没太懂)sealed class SeasonSealed { //密封类内部的每个嵌套类都必须继承该类 class Spring(var name: String):SeasonSealed() class Summer(var name: String):SeasonSealed() class Autumn(var name: String):SeasonSealed() class Winter(var name: String):SeasonSealed() }when(season){ is SeasonSealed.Spring ->season.name is SeasonSealed.Autumn ->season.name is SeasonSealed.Summer ->season.name is SeasonSealed.Winter ->season.name }数据类只需要在class前面加关键字data
data class Plant(var name:String, var stem:String, var leaf:String, var flower:String, var fruit:String, var seed:String) { }外部调用
var lotus =Plant("莲","莲藕","莲花","莲蓬","莲子","莲叶"); var count:Int=0 var lotus2=when(count++%2){ //copy方法带参数,表示指定参数另外赋值,不带参数表示赋值的一模一样 0-> lotus.copy(flower = "荷花") 1->lotus.copy() else ->lotus.copy(flower = "莲花") } var result = if(lotus.equals(lotus2)) "相等" else "不相等" var text1 = lotus.toString() var text2 = lotus2.toString()模板类在类名后年添加“”,表示这是一个模板类
class River(var name:String,var length:T) { fun getInfo():String{ var unit:String = when(length){ is String ->"米" // Int Double.Float,都是Number类型 is Number ->"m" else ->"" } return "${name} 的长度是$length $unit" } } var count:Int=0 var lotus2=when(count++%2){ //末班对声明对象时,要在模板类的类名后面加上“参数类型” 0->River("小溪",100) //如果编译器根据输入参数就能知晓参数类型也可以省略“参数类型” 1->River("山间",99.5f) else -> River("大河","一千") }



