【Kotlin入门教程】史上最全最易于理解最全面的文章

在这里插入图片描述

前言

由于在自己面试过程中,经常被问到有没有学过kotlin,总感觉自己少了点东西,于是就花了一个多星期将最基本的kotlin知识点给学了一遍,本篇文章仅仅含有一点点Android的知识,并不是学习Android的好文章,但是是最快入门kotlin的一篇全面的文章,当然,我也希望大家与我共同学习进步,如果有什么疑问,或者经验交流,都可以加群QQ:1098392728与我们交流。
更多好文章可以去浏览我的个人博客WilliamTao的博客

Kotlin学习笔记

1.val和var区别

val 可以理解为java中的final关键字,只能在声明的时候赋值

var 在任何时候都可以赋值

2.简单变量之间的转换

//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<String>=arrayListOf("hello","world")
    
}

其实,上面图片的内容都可以不用,直接使用Array 《》括起来就可以了

数组的获取,可以通过java的中括号,也可以使用get来获取

 var string_array:Array<String>=arrayOf("hello","world")
    Btn_test.setOnClickListener{
            var str :String=""
            var i:Int = 0
            while(i<string_array.size){
              str=str+string_array.get(i)+","
                i++
               // str=str+string_array[i]+","
            }
            textView.text=str
            println(str)
        }

4.字符串

字符串与基本类型的转换

kotlin方便一点,便于记忆

var test:String="1"
println(test.toInt())

字符串常用方法

  • indexOf
  • substring
  • split:在Java里返回的是String[],而在kotlin中返回的是List
  • 通过下标获取某个位置的字符
 var orgin:String ="he.llo.wor.ld"
         var list:List<String> =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

公共方法

kotlin允许对容器进行初始化,而java不可以

集合Set/MutableSet

  1. 循环的方法:
  2. for
  3. 迭代器

//方法一
var setList: Set<String> = 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<String> = listOf("test", "second", "thrid")
for (i in ListList.indices) {
    var item =ListList[i]
    println("名称: $item")
}

list中还提供了两种排序的函数 分别为:

  • sortBy
  • sortedByDescending
   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<String,String> = mapOf("苹果" to "Iphone 12","Android" to "VIVO") 
        var godMap2:MutableMap<String,String> = 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
  • 数值 -> 代替了case
  • else替代了default
  • kotlin中每一个 分支自动跳出
  • 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<n;i++) 这种形式,并且kotlin提供了两种方式

  1. 变量 in …
  2. for(i in 容器.indices)
//方法一   
var list:Array<String> = arrayOf<String>("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山")

        Btn_test.setOnClickListener {
            var poem:String=""
            for(item in list){
            poem = "$poem$item,\n "
         }
            textView.text = poem
        }
//方法二
    var list:Array<String> = arrayOf<String>("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山")

        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<String> = arrayOf<String>("朝辞白帝彩云间","千里江陵一日还","两岸猿声啼不住","轻舟已过万重山")
        var i:Int=0
        while(i<list.size){
            println(list[i]+"--")
            i++
        }
        println("-----------")
        i=0
        do{
            println(list[i]+"**")
            i++
        }while (i<list.size)

跳出多重循环

低配版本

  //这里有空语句所以注意时Array<String?> 而非Array<String>
        var list:Array<String?> = 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<String?> 而非Array<String>
var list:Array<String?> = arrayOf("朝辞白帝彩云间",null,"千里江陵一日还","","   ","两岸猿声啼不住","轻舟已过万重山")

Btn_test.setOnClickListener {
    var i:Int=0
    var is_found =false
    //给外循环加一个名叫outside的标记
    outside@ while (i<list.size){
        var j:Int=0
        var item=list[i];

        if (item != null) {
            while(j<item.length){
                if(item[j] == '一'){
                    is_found=true
                    break@outside
                }
                j++;
            }
        }
    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<String>){
    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.泛型函数

泛型函数

fun <T> appendString(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<String>("古代四代发明","造纸术","硬刷术","火药","指南针")
    1-> appendString<Int>("古代四代发明",1,2,3);
    else -> appendString<Double>("古代四代发明",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:Array<String> = 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})}")

lambda函数

看前面的有个,{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<String> = 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 <T>(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<Int>("小溪",100)
    //如果编译器根据输入参数就能知晓参数类型也可以省略“参数类型”
    1->River("山间",99.5f)
    else -> River("大河","一千")
 }

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

William_Tao(攻城狮)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值