Kotlin学习(二)

2.kotlin学习(二)

1.条件控制

package com.simon.second

fun main(args: Array<String>) {
    //if
    var a = 1
    var b = 2
    var max:Int
    if (a > b){
        max = a
    }else{
        max = b
    }
    //作为表达式结果赋值给max1 感觉这个简单啊
    var max1 = if(a>b)a else b
    println(max)
    println(max1)

    //同样可以和区间一起
    var x = 6
    if( x in 1..6) println("x在区间里面")
    //when when类似于其他语言的switch
    when(x){
        1,3 -> println("x==1 or x==3")
        2 -> println("x==2")
        //区间也可以
        in 4..5 -> println("4<=x<=5")
        //可以类型判断也基本上就是判断式都ok
        is Int -> println("x是数字")
        else ->{
            println("x是其他数字")
        }
    }
    //还能判断集合中是否存在
    var items = setOf<String>("apple","banana")
    when{
        "banana" in items -> println("banana in items")
        "apple" in items -> println("apple in items")
    }

}

if和java差不多

when类似于switch

2.循环控制

package com.simon.second

fun main(args: Array<String>) {
    //for循环可以对任何提供迭代器对象来便利
    //for(item in collection)print(item)
    val ints:Array<Int> = arrayOf(1,2,3)
    for (item in ints){
        print(item)
    }
    //如果想通过索引来读(会编译优化,也可以选择下面这个方式)
    for(i in ints.indices){
        print(ints[i])
    }
    println()
    for((index,item) in ints.withIndex()){
        print("$index:$item ")
    }
    //while 和 doWhile循环
//    while (布尔表达式){
//        //内容
//    }
//    do{
//        //内容
//    }while (布尔表达式)
    var x = 5
    while (x>0){
        println(x--)
    }

    var y = 5
    do {
        println(y--)
    }while (y > 0)

    test1()

    foo()
}
fun test():Int{
    //return break 和 continue
    for (i in 1..10){
        if (i == 3)continue
        println(i)
        if (i>5)break
    }
    return 10
}

//Break和Continue标签
//这个爽炸了,直接跳指定循环舒服了
//continue同理跳到指定循环
fun test1(){
    loop@ for(i in 1..100){
        loop1@for (j in 1..100){
            if (i == j) {
                println("i==j")
                break@loop
            }
        }
    }
}
//标签处返回
//举个例子
fun foo(){
    var ints:Array<Int> = arrayOf(1,2,3)
    //如果没有标签处返回就会返回整个函数的返回,如果是有标签就会是标签处返回
    ints.forEach lit@{
        if (it == 3) return@lit
        println(it)
    }
    //lambda表达式使用隐式标签
    ints.forEach {
        if (it == 2) return@forEach
        print(it)
    }
    //匿名函数
    var x = ints.forEach(fun(value:Int){
        if (value == 2) return@forEach
        print(value)
    })
        
    
}

标签蛮有意思的可以多看看

感觉kotlin的lambda还是有点看不懂啊

3.类和对象

package com.simon.second

import kotlin.properties.Delegates

class Empty {}
class Runoob {
    //类的属性
    var name:String = "simon"
    var url:String = "www.baidu.com"
    var city:String = "赣州"
    //创建对象
    val site = Runoob()
    //成员函数
    fun foo(){
        println("foo is use")
       //调用属性
        println(site.city)
        println(site.name)
        println(site.url)
    }
}
//kotlin里面可以有一个主构造器以及一个或者多个此构造器,主构造器是类头部的一部分
class Person constructor(firstName:String){}
//如果主钩早期没有任何注解或者可见度修饰符那么可以省略构造器关键词
class Person1(firstName: String){}
//定义了一个Person2类,包含两个可变变量,lastName和no,lastName而修改了getter,no修改了setter
class Person2{
    var lastName:String = "zhang"
        get() = field.toUpperCase() //将变量赋值后转化为大写
        set

    var no:Int = 100
        get() = field
        set(value){
            field = if (value<10) value else -1
        }
    //不可见
    var heiht:Float = 145.4f
        private set

    //backing filed 后备变量
    //例如下面一种情况
//    var name:String = "HelloWorld"
//        get() = name

    var name:String = ""
        get() = field
        set(value){
            field = value
        }

    //另外还有一个非空属性的延迟加载

}

fun main(args: Array<String>) {
    var ps = Person2()
    println(ps.lastName)
    ps.no = 10
    println(ps.no)
//    ps.heiht = 10.2f
    //报错set是private
    println(ps.heiht)
    //后备变量

    /*
    * 我造!怎么溢出了??
    * println(ps.name)
    * 梳理下逻辑
    * 我ps.name调用name属性的get方法获取值,发现还是name属性,那继续get,自然就溢出了
    * set同理
    * 那这样我们就在外部如何访问修改他的值呢???
    * 这个时候后备变量就起作用了!
    * 也就是我们的变量的值就是filed的值
    * 我们属性使用会自动地调用set get方法
    * 但是这下就不会了
    * */
    ps.name = "Hello kotlin"
    println(ps.name)
}


package com.simon.second
//1.延时加载 lateinit
class MyTest {
    //我们的lateinit是用于延时加载我们的非基本类型的变量
    lateinit var myVar:String
    //我们的基本数据类型想要被延时加载可以像下面这样用
    var myInt:Int? = null
    //也就是允许为null且赋值为null

    fun checkMyVar(){
        if (::myVar.isInitialized){
            println(myVar)
        }else{
            println("未被初始化")
        }
    }

}
//2.我们的主构造器没有其他构造器那样有一个程序段所以我们可以在构造的时候使用init关键字
class Person3 constructor(firstName: String) {
    var name:String = firstName
    var age:Int?=null

    init {
        println("FirstName is $firstName")
    }
    //次构造器,我们就需要加前缀constructor
    //并且我们的次构造器需要先去代理主构造函数,同一个类里面代理主构造函数就使用this关键字
    constructor (name: String, age:Int) : this(name) {
        this.age = age
    }
}
//3.我们定义了一个类之后会默认有无参构造,如果想要隐藏构造器可以这样操作(私有化)
class DontCreateMe private constructor () {
}

//4.抽象类
abstract class Derived  {
    abstract fun f()
}

//5.嵌套类
class Outer {                  // 外部类
    private val bar: Int = 1
    class Nested {
        var str:String = "simon"
        // 嵌套类
        fun foo() = 2
    }
    //那么我们的嵌套类与我们的内部类有什么区别呢?
}
//6.内部类
class Outer1{
    private val bar:Int = 2
    //内部类
    inner class Nested1{
        var str:String = "innerSimon"
        fun getBar():Int{return this@Outer1.bar}
    }
}
//7.匿名内部类
interface TestInterFace{
    fun test()
}
class Test{
    var v = "成员属性"
    fun setInterFace(test: TestInterFace){
        //我们可以看到我们的这个参数是这个接口
        test.test()
    }
}

//8.类的修饰符
/**
 * 属性修饰符
 * abstract 抽象类
 * final 类不可继承
 * enum 枚举类
 * open 类可继承 默认类是final的
 * annotation 注解类
 * 访问修饰符
 * private 一个文件可以
 *protected 同一个文件或者子类可见
 * public 所有调用的地方都可以见
 * internal 同一个模块中可见
 *
 * */


fun main(args: Array<String>) {
    var myTest = MyTest()
    myTest.checkMyVar()

    myTest.myVar = "hello kotlin"
    myTest.checkMyVar()

    var person = Person3("simon")

    var person2 = Person3("simon2",5)

    println(person2.name)
    println(person2.age)
    //嵌套类
    var nest = Outer.Nested()
    println(nest.foo())
    //外部和内部元素均无法互相访问

    //内部类
    //我们内部类的对象在获取时也要初始化我们的外部类对象
    //(可能用到外部类的属性所以也要获取实例)
    //外部无法访问内部但是内部可以访问外部
    var bar = Outer1().Nested1().getBar()
    //我们外部对象访问不了内部的str属性
//    var str = Outer1().str
    println(bar)

    //匿名内部类
    /*
    * 采用对象表达式来创建接口对象,即匿名内部类的实例
    * */
    var test = Test()
    test.setInterFace(object : TestInterFace{
        override fun test() {
            println("对象表达式创建匿名内部类的实例")
        }
    })
}

主要注意:

延时加载、主次构造器(次无论如何都会走主代理)、后备变量、init、嵌套类和内部类

4.继承

我们要知道我们Kotlin中所有类都继承Any类(类似java的Object)

Any提供了三个函数

equals hashCode toString

注:Any不是java.lang.Object

package com.simon.second

import javax.naming.Context

//基本的继承演示
open class Base(p:Int)
class BaseDerived(p:Int):Base(p){}

//1.如果子类有主构造函数,则基本必须在主构造函数中立刻初始化
open class Person5(var name:String,var age:Int){
    //要声明出来可以被重写
    open fun study(){
        println("我毕业了")
    }
}

class Student(name: String,age: Int,var no:String,var score:Int):Person5(name,age){}
//个人理解就是:如果基类主构造函数有这两个字段,那么我们的子类在声明时也必须吧这个字段带入自己的主构造函数

//2.如果子类没有主构造函数
//class Student1():Person5(name = "simon",12){
//
//}
//就像上面上的必须马上初始化就直接赋值给基类的主构造函数
//或者像下面在次构造里面写一个super基类的构造方法
class Student2: Person5{
    //也就是我只有这个有参构造,构造的同时调用父类的主构造方法
    constructor(name: String,age: Int):super(name,age){}
    //3.重写方法
    override fun study() {
        println("我还在读书")
    }
}
//4.重写属性(一般用不上了解就行)
interface Foo{
    val count:Int
}
//将一个val属性重写为var(常-》变)
//不能变量变成常量
class Bar1(override var count:Int):Foo
//将属性重写属性和值
class Bar2 : Foo {
    override var count: Int = 1
}

fun main(args: Array<String>) {
    var s = Student("Runoob",18,"s123",89)
    println("${s.name}")
    println("${s.age}")
    println("${s.no}")
    println("${s.score}")
    //重写
    var s2 = Student2("simon",19)
    s2.study()

}

5.接口

Kotlin中的接口与java8类似,允许方法有默认实现

package com.simon.second

import javax.naming.Context

//基本的继承演示
open class Base(p:Int)
class BaseDerived(p:Int):Base(p){}

//1.如果子类有主构造函数,则基本必须在主构造函数中立刻初始化
open class Person5(var name:String,var age:Int){
    //要声明出来可以被重写
    open fun study(){
        println("我毕业了")
    }
}

class Student(name: String,age: Int,var no:String,var score:Int):Person5(name,age){}
//个人理解就是:如果基类主构造函数有这两个字段,那么我们的子类在声明时也必须吧这个字段带入自己的主构造函数

//2.如果子类没有主构造函数
//class Student1():Person5(name = "simon",12){
//
//}
//就像上面上的必须马上初始化就直接赋值给基类的主构造函数
//或者像下面在次构造里面写一个super基类的构造方法
class Student2: Person5{
    //也就是我只有这个有参构造,构造的同时调用父类的主构造方法
    constructor(name: String,age: Int):super(name,age){}
    //3.重写方法
    override fun study() {
        println("我还在读书")
    }
}
//4.重写属性(一般用不上了解就行)
interface Foo{
    val count:Int
}
//将一个val属性重写为var(常-》变)
//不能变量变成常量
class Bar1(override var count:Int):Foo
//将属性重写属性和值
class Bar2 : Foo {
    override var count: Int = 1
}

fun main(args: Array<String>) {
    var s = Student("Runoob",18,"s123",89)
    println("${s.name}")
    println("${s.age}")
    println("${s.no}")
    println("${s.score}")
    //重写
    var s2 = Student2("simon",19)
    s2.study()

}

6.扩展

package com.simon.second

class User(var name:String)
//1.扩展函数
fun User.Print(){
    println("用户名:${name}")
}
//2.扩展函数swap
fun MutableList<Int>.swap(index1:Int,index2:Int){
    var tmp = this[index1]
    this[index1] = this[index2]
    this[index2] = tmp
}
//3.扩展函数是静态解析的(具体是哪个对象调用就是哪个对象的扩展函数)和动态绑定正好不一样
open class D
class E: D()
fun C.foo() = "C"

fun D.foo() = "D"
fun printFoo(d: D){
    println(d.foo())
}
//4.还可以扩展一个空对象,使用Any那不是所有类的toString都会判空了?
fun Any?.toString():String{
    if (this == null)return "null"
    return toString()
}
//5.伴生对象的扩展(方法和属性)
class MyClass{
    companion object{

    }
}

fun MyClass.Companion.foo(){
    println("伴生对象的方法扩展")
}

val MyClass.Companion.id: Int
    get() = 1
//6.作用域也可以扩展,懒得分包了不掩饰了

//7.扩展声明为成员
class F{
    fun bar(){
        println("F bar")
    }

    fun G.foo(){
        barG()
        bar()
    }

    fun caller(g:G){
        g.foo()
    }

}
class G{
    fun barG(){
        println("G bar")
    }
}

fun main(args: Array<String>) {
    var user = User("simon")
    user.Print()

    var l = mutableListOf(1,2,3)
    l.swap(0,2)
    println(l.toString())
    //虽然传的是D对象,但是接受的是C对象,所以调用的是C的foo,所以为静态的
    printFoo(E())

    println(MyClass.foo())
    println(MyClass.id)

    var g = G()
    var f = F()
    f.caller(g)

}

8.数据类和密封类

package com.simon.second

import kotlin.math.exp

//1.数据类 只包含数据的类

data class UserInfo(val name:String, val age:Int)
//equals,hashCode,toString,componentN,copy
//上面四个不说了演示下copy
//标准库提供了pair和triple但是实际上数据类设计更加完善

//2.密封类(这个蛮有意思的,同样是对有限类型的限制,举个例子)
//我们内嵌的子类定义了两个状态,一个是关闭一个是开启
//那么我们配合when对我们的这个op按钮类型进行判断
sealed class UiOp {
    object Show: UiOp()
    object Hide: UiOp()
    class TranslateX(val px: Float): UiOp()
    class TranslateY(val px: Float): UiOp()
}
fun execute(view: View, op: UiOp) = when (op) {
    UiOp.Show -> view.visibility = View.VISIBLE
    UiOp.Hide -> view.visibility = View.GONE
    is UiOp.TranslateX -> view.translationX = op.px // 这个 when 语句分支不仅告诉 view 要水平移动,还告诉 view 需要移动多少距离,这是枚举等 Java 传统思想不容易实现的
    is UiOp.TranslateY -> view.translationY = op.px
}

class View {
    companion object{
        const val VISIBLE = true
        const val GONE = false
    }

    var translationY: Float = 0.0f
    var translationX: Float = 0.0f
    var visibility:Boolean = true
}

fun main(args: Array<String>) {
    val cp1 = UserInfo("simon",13);
    val cp2 = cp1.copy(name = "simon1",14)
    println(cp1.toString()+cp2.toString())
    //解构
    val (name,age) = cp2

    //
}

感觉密封类和枚举类似但是密封类可以携带数据

你可能感兴趣的:(kotlin,学习)