1.Kotlin基础概念

基本概念

修饰符

  • public:默认限定符,可以省略不写
  • private
  • protected
  • internal:同模块限定符;同一module可以调用被internal修饰的方法,跨module不行。

数据类型

  • 字节 : byte
  • 浮点型 : double,float
  • 整型 : long,int,short

对象修饰符

  • 变量是var修饰;

  • 被var修饰的属性会自动生成get和set方法

  • 常量val修饰。

  • Kotlin中被val修饰的属性会自动生成get方法

变量和方法

变量
// 声明
val num: Int = 8 // 声明并立即赋值
var a = 1 // 自动推断出 `Int` 类型;    变量可以不需要声明类型,光标停留在变量上时按Ctrl+Q可以查看变量类型
val valTest: Int //变量如果没有初始值类型不能省略
方法
 private fun helloworld(arg: String = "123321"): String {
        println(arg)
        return arg
    }

在java中函数的形参只能是接口类型,不能是接口中的方法类型,但在Kotlin中,方法形参的类型可以是接口中的方法:

fun example(mRun: () -> Runnable) {
        //局部变量还可以是接口中的一个方法
        val r by lazy(mRun)
        r.run()
    }    

get和set

class KtTest {
    var name = ""
        //替换自动生成的set和get方法
        set(value) {
            field = value.toLowerCase()
        }
        get() {
            return field.toUpperCase()
        }
}
  • Kotlin中被val修饰的属性会自动生成get方法,被var修饰的属性会自动生成get和set方法

静态变量和方法

companion : 伴生对象
  • companion object {}中用来修饰 静态常量,或者静态方法,单例等等
  • companion object 修饰为伴生对象,这个对象被这个类的所有对象所共享且只能存在一个,但并不是静态属性或方法,只是创建Companion静态对象来调用里面的属性和方法
  • companion object 中调用不到外部成员变量,如同java中的静态方法无法调用非静态的成员变量,想调用则将所引用的成员变量也修饰静态的
静态变量
  const val text = ""(需要注意的是要把静态变量定义在类上方)

或者

  class StaticDemoActivity {
      companion object {
           val  LOAN_TYPE = "loanType"
           val  LOAN_TITLE = "loanTitle"
    }
}

或者

  class StaticDemoActivity {
      companion object StaticParams{
            val  LOAN_TYPE = "loanType"
            val  LOAN_TITLE = "loanTitle"
    }
}

 或者
  class StaticDemoActivity {
      companion object {
         const val LOAN_TYPE = "loanType"
         const val LOAN_TITLE = "loanTitle"
    }
}

注意: const 关键字用来修饰常量,且只能修饰 val,不能修饰var, companion object 的名字可以省略,可以使用 Companion来指代

kotlin 中调用

StaticDemoActivity.LOAN_TYPE

java中调用

class TestEntity {
        public TestEntity () {
            String title = StaticDemoActivity.Companion.getLOAN_TITLE();
    }
  }

  或者

  class TestEntity {
        public TestEntity () {
            String title = StaticDemoActivity.StaticParams.getLOAN_TITLE();
        }
  }

  或者

  class TestEntity {
        public TestEntity () {
            String title = StaticDemoActivity.LOAN_TITLE;
            String type= StaticDemoActivity.LOAN_TYPE;
        }
  }
静态方法

静态方法作用域

// 定义静态方法的方式一,定义顶层方法(在类之外进行定义)
fun staticMethod1(){

}
 companion object {
        //伴生方法,类似静态方法
        fun companionMethod(){}
        //定义静态方法的方式二,加静态注解
        @JvmStatic
        fun staticMethod2(){}
        fun b() {Log.e(TAG,"此时 companion objec t表示 伴生对象")}
    }

kotlin 中调用

fun init(){b()}

java 中调用

DemoManager.Companion.b();

内部类(inner)

class Outter{
    var a=5

    class NotInner{
        fun m1(i: Int):Int {
//            a=i  编译不通过
            return i + 1
        }
    }

    //inner修饰过的内部类可以访问外部内成员变量
    inner class WithInner{
        fun m2(i: Int):Int {
            a=i
            return a
        }
    }
}
  • kotlin内部类默认为静态的,inner修饰的内部类是非静态的
  • 内部类引用外部类 this@外部类类名
  • 外部类引用内部类 this@内部类类名
生成匿名内部类对象
class abc {}

val textView = findViewById<TextView>(R.id.tv)
textView.setOnClickListener(object : abc(),OnClickListener {
        override fun onClick(p0: View?) {
            Toast.makeText(this@TestActivity, "点击事件生效", Toast.LENGTH_LONG)
        }

})
  • 在匿名内部类实现的过程中,还可以实现集成abc类

密封类(sealed)

sealed class Son {
    //小驴继承于Son
    class 小驴() : Son()
    //小骡继承于Son
    class 小骡() : Son()

    fun sayHello() {
        println("儿子叫了")
    }
}
  • 限制子类个数,子类可数,外部其他类无法继承该Son类
  • 而枚举是限制实例个数,实例可数
  • Kotlin1.1之前子类必须写在外部类内部,之后,可以写在外部类外部

构造函数

//普通类
class Invoice {
}

//带主构造函数的类
class Person constructor(firstName: String) {
}
//如果主构造函数没有注解或可见性说明,则 constructor 关键字是可以省略的
class Person(firstName: String) {
}
//如果构造函数有注解或可见性声明,则 constructor 关键字是不可少的,并且可见性应该在前
class Customer public @inject constructor (name: String) {...}

//主构造函数不能包含任意代码。初始化代码可以放在以 init 做前缀的初始化块内
class Customer(name: String) {
    init {
        println("Customer initialized with value ${name}")
    }
}
//主构造函数的参数可以用在初始化块内,也可以用在类的属性初始化声明处
class Customer(name: String) {
    val customerName = name
}
//主构造函数中可以同时声明属性并进行初始化
//类如果没有类体可以省略大括号
class Customer(val customerName: String) 

//在class前面加data修饰,Kotlin会给该类自动生成copy、toString、hashCode、equals四个方法
data class Customer(val customerName: String) 
二级构造函数
//类也可以有二级构造函数,需要加前缀 constructor
//如果类有主构造函数,每个二级构造函数都要直接或间接通过另一个二级构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字
class Person (firstName: String) {
    constructor(firstName: String, secondName: String) : this(firstName){
          ...
    }
}

/*在 JVM 虚拟机中,如果主构造函数的所有参数都有默认值,
编译器会生成一个附加的无参的构造函数,这个构造函数会直接使用默认值。
这使得 Kotlin 可以更简单的使用无参构造函数来创建类实例的库*/
class Customer(val customerName: String = "")


创建类对象

//创建实例, Kotlin 没有 new 关键字
val c = Customer()
val p = Person("小明")

继承

  • Kotlin 中所有的类都有共同的父类 Any ,它是一个没有父类声明的类的默认父类:
  • class Example // 隐式继承于 Any
  • open注解与java中的final相反:它允许别的类继承这个类。默认情形下,kotlin 中所有的类都是 final
//如果类有主构造函数,则父类必须在主构造函数中使用参数立即初始化。
open class Base(p: Int)
class Derived(p: Int) : Base(p)

class Derived() : Base() {}//对于有无参数构造方法的父类,继承时可以使用无参构造方法立即初始化


/*如果类没有主构造函数,则必须在每一个构造函数中用 super 关键字初始化基类,
或者代理另一个构造函数做这件事。注意在这种情形中不同的二级构造函数
可以调用基类不同的构造方法:*/  
class MyView : View {
    constructor(ctx: Context) : super(ctx) {
    }
    constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
    }
}


// 没有主构造函数且没有其它构造函数,则父类可以进行立即初始化
  class Derived : Base() {}

总结 :

  • 在继承中,主要看当前类是否有主构造函数,有的话则父类必须在主构造函数中使用参数立即初始化;没有的话,则必须在每一个构造函数中用 super 关键字初始化基类
  • 当前类是没有主构造函数且没有其它构造函数,则父类可以进行立即初始化

复写

复写方法
//在 kotlin 中坚持做明确的事,不像 java ,kotlin 需要把可以复写的成员都明确注解出来,并且重写它们:
open class Base {
    open fun v() {}
    fun nv() {}
}
//对于有无参数构造方法的父类,继承时可以使用无参构造方法立即初始化
class Derived() : Base() {
    override fun v() {}
}

注意:对于 Derived.v() 来说override注解是必须的。如果没有加的话,编译器会提示。如果没有open注解,像 Base.nv() ,在子类中声明一个同样的函数是不合法的,要么加override要么不要复写。在 final 类(没加open注解的类)中,open 类型的成员是不允许的。

open class AnotherDerived() : Base() {
    final override fun v() {}
}
  • 假如当前类实现了父类的方法,该方法会标记为override修饰的,且该成员是open的,它可以在子类中被复写。如果你不想被重写就要加 final
复写属性
open class Foo {
  open val x: Int = 3
}
class Bar1 : Foo() {
  override val x: Int = 9
}
//主构造函数中复写属性,使用override关键字作为属性声明的一部分
class Bar2(override val x: Int) : Foo() {
}
  • 属性的复写,可以在类中也可以在主构造函数中
多继承中两个父类方法相同
open class A {
    open fun f () { print("A") }
    fun a() { print("a") }
}

interface B {
    fun f() { print("B") } // 接口的成员变量默认是 open 的
    fun b() { print("b") }
}

class C() : A() , B {
    // 编译器不知道应该选哪个f方法,会要求复写f()
    override fun f() {
        super<A>.f() // 调用 A.f()
        super<B>.f() // 调用 B.f()
    }
}

抽象类

open class Base {
    open fun f() {}
}

abstract class Derived : Base() {
    override abstract fun f()
}
  • 一个类或一些成员可能被声明成 abstract 。一个抽象方法在它的类中没有实现方法。记住我们不用给一个抽象类或函数添加 open 注解,它默认是带着的。
  • 可以在抽象类中去复写父类中带 open 注解的非抽象方法

接口

接口中的方法
interface MyInterface {
    fun bar()
    fun foo() {
        //函数体是可选的
                println("foo")
    }
}

//接口的实现
//一个类或对象可以实现一个或多个接口,用,隔开
class Child : MyInterface {
        //没有默认实现的方法必须重写 
        override fun bar () {
        //函数体
    }
}
  • 与Java不同,可以有方法体
接口中的成员变量
//与Java中接口中属性必须为常量不一样的是Kotlin接口中的属性可以是抽象的
interface MyInterface {
        //抽象的属性
    val property: Int // abstract
    //提供访问器的实现的属性,和Java中常量类似
    val propertyWithImplementation: String
        get() = "foo"

    fun foo() { 
        print(property)
    } 
}
//实现接口
class Child : MyInterface { 
    override val property: Int = 29
}
  • 与Java不同,成员变量可以不赋值

字符串

//三重引号(""")分隔,原始字符串可以包含换行符和任何其他字符,都会原样输出
val rawString = """\a/b\\c//d"""
//字符串模板表达式:以美元符号($)连接变量,方便字符串拼接
        val s = "Hello"
        val templateString = "$s has ${s.length} characters"
        println(templateString) //Hello has 5 characters

判断

is
  • is是java中的 instanceof,且内部不需要强制转换了
        if (arg is String) {
            // `result` 在该条件分支内自动转换成 `String`
            // 无需再进行强制转换
            println(arg::class) //class kotlin.String
            val length = arg.length
            println(length)
        }
        
        
 // `||` 右侧的 x 自动转换为字符串
    if (x !is String || x.length == 0) return

    // `&&` 右侧的 x 自动转换为字符串
    if (x is String && x.length > 0) {
        print(x.length) // x 自动转换为字符串
    }
  • val 局部变量——总是可以;
  • val 属性——如果属性是 private 或internal,或者该检查在声明属性的同一模块中执行
  • 智能转换不适用于 open的属性或者具有自定义 getter 的属性;var 局部变量——如果变量在检查和使用之间没有修改、并且没有在会修改它的 lambda 中捕获;
  • var 属性——决不可能(因为该变量可以随时被其他代码修改)
as
  • as 类似java中的强制转换
//如果类型转换不成功,类型转换操作符通常会抛出一个异常
val x: String = y as String//y不可为空

//当 y = null 时,不会抛异常;但是,当类型转换失败时,还是会崩溃
val x: String? = y as String?//y可为空

//当类型转换失败时,它会返回 null,但不会抛出异常崩溃
val x: String? = y as? String//转换失败时返回 null
if…else…
fun test() {
        val a = 100
        val b = 87
        //if else会将执行最后一行代码的结果作为返回值返回
        val bigger = if (a > b) {
            a
        } else {
            b
        }
        //只有一行代码方法体的括号可以去掉
        val bigger1 = if (a>b) a else b
    }
when(替换Java中switch)
//when里面可以传任何对象,对多重类型都能够进行支持
    fun test(arg: Any) {
      when (arg) {
            0 -> print("OK")
            in 1..8 -> print("1..8")
            "OK", "Success" -> print("OK")
            "Hello" -> {
                println("Hello")
                print("World!")
            }
            is Button -> print("is Button")
            //when有返回值
            var str = when {
            x < 5 -> "小于5"
            else -> "大于等于 5"//注意返回值要完备
            }
            else -> {
                print("End")
            }
            
        }
    }

for循环

   //Kotlin中取消了Java中的for i循环
    fun loopTest() {
        //for in循环
        for (i in 0..100) { //0<=i<=100

        }
        for (i in 0 until 100) { //0<=i<100

        }
        
        for (i in 10 downTo 0){//倒序输出
        println(i)
        }
        >>>109876543210

        for (i in 0 .. 10 step 2){//间隔跳跃输出
        print(i)
        }
        >>>0246810

        val list = listOf("a", "b", "c")//转集合
        for (i in list) {//遍历集合元素
            print(i)//a b c
        }
        
        var abc = listOf("a","b","c")
        for (index in abc.indices){//遍历集合角标
        print("$index")
        }
        >>>012
        
         val array = arrayListOf("1", "2", "3")//转数组
        for (i in array.indices) {//遍历数组角标
            println(array[i])
        }
        //区间写法
        for (i in IntRange(1, array.size - 1)) {
            println(array[i])
        }
        //it为集合对象
        list.forEach {
            print(it) //a b c
        }
        //index为集合下标,s为集合对象
        list.forEachIndexed { index, s ->

        }
        
        for ((index,value) in abc.withIndex()){//遍历数集合元素和角标
        print("$index:$value ")
        }
        >>>
        0:a 1:b 2:c 
    }
跳出for循环的两种方式
label@for  (i in 0 until 3) {
                if (i == 1)
                    break@label
            }

            for  (i in 0 until 3) {
                if (i == 1)
                    break
            }
  • while循环、do…while循环和Java中完全一样,这里就省略了

参考资料:

[Kotlin插件安装] https://www.jianshu.com/p/c37a1e7f30d6

[Kotlin基本介绍] https://www.jianshu.com/p/1c83bd577cbb

[Kotlin类与对象] https://www.jianshu.com/p/6ee0fd185a89

[anko] https://www.jianshu.com/p/d30406daaf25

[anko] https://www.jianshu.com/p/d94c48cdca4e

[Kotlin中的object 与companion object的区别] https://www.jianshu.com/p/14db81e1576a

[Kotlin中常量和静态方法] https://www.jianshu.com/p/e8752c880088

[Generate Kotlin data classes from JSON 安装与使用] https://www.jianshu.com/p/5b1f2c724628


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值