kotlin学习笔记

Kotlin是一门与Swift类似的静态类型JVM语言,由软件公司JetBrains设计开发并开源

 

为何说Kotlin非常适合于Android?

1.体积小,其大小相当于support-v4库

2.同一家公司的IDE和语言,所以IDE对该语言提供了非常棒的支持

3.互操作性是非常智能,Kotlin代码中使用Android SDK而不会遇到任何问题

特性:

1.Null安全

2.数据类

3.互操作

4.Lambda表达式

补充:

1.POJO:简单的Java对象(Plain Old Java Object)

 

Kotlin学习笔记资料:

kotlin函数定义:

1.在Java中,所有的控制结构都是语句,而在Kotlin中,除了for、do和do/while以外大多数控制结构都是表达式。

2.表达式和语句区别:表达式有值,并且能作为另一个表达式的一部分使用。而语句无值,并总是包含着它的代码块中的顶层元素。

3.函数体写在花括号中,则这个函数有代码块体

4.直接返回了一个表达式的,则它就有表达式体

5.对于表达式体函数,可以省略返回类型,因为编译器会分析作为函数体的表达式,并把它的类型作为函数的返回类型,这种分析称为 类型推导。但是对于有返回值的 代码块体函数,必须显示地写出返回类型和return语句。

fun main(args: Array<String>) {
    println("值:"+max(1, 5))//值:5
}
​
fun max(a: Int, b: Int): Int{
    return if(a > b) a else b
}
 

变量声明:使用关键字val或val声明

val:不可变引用 

var:可变引用

 

字符串模板处理:

fun main(args: Array<String>) {
    //直接引用局部变量
    val name = if(args.size > 0) args[0] else "Kotlin"
    println("嘿嘿,$name")//嘿嘿,Kotlin

    //在字符串中使用$,需要对它进行转义
    val money = 50;
    println("有钱,\$$money")//有钱,$50

    //引用更加复杂的表达式,需要把表达式用花括号扩起来
    println("a is ${if(5 > 6) "bigger" else "smaller"} than b")
}
 

类定义:

1.在Kotlin中,属性是头等的语言特性,完全替代了字段和访问器方法

fun main(args: Array<String>) {
    personFunc()
}
​
class Person(val name: String, var isMarried: Boolean)
​
fun personFunc(){
    val person = Person("zemao", false)
    println("${person.name} isMarried = ${person.isMarried}")//zemao isMarried = false

    person.isMarried = true
    println("${person.name} isMarried = ${person.isMarried}")//zemao isMarried = true
}
 

类自定义访问器:

fun main(args: Array<String>) {
    val rectangle = Rectangle(41, 43)
    println(rectangle.isSquare)//false
    rectangle.height = 43
    println(rectangle.isSquare)//true
}
​
class Rectangle(var height: Int, var width: Int){
    val isSquare:Boolean
    get() = height == width
}
 

枚举:

1.声明枚举类时,enum是一个软关键字,只有当它出现在class前面时才有特殊的意义,在其他地方可以当做普通名称使用,而class仍然是一个关键字。

2.声明一个带属性的枚举类时需要注意:

1)当声明每个枚举常量的时候,必须提供该常量的属性值。

2)如果要在枚举类中定义任何方法,就要使用分号把枚举常量列表和方法分开。

fun main(args: Array<String>) {
    println(Color.BLUE.rgb())//255
}
​
//不带属性的枚举类
// enum class Color{
//     RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
// }
​
​
//带属性的枚举类
enum class Color(var r: Int, val g: Int, val b: Int){
    RED(255, 0, 0), 
    ORANGE(255, 155, 0), 
    YELLOW(255, 255, 0), 
    GREEN(0, 255, 0), 
    BLUE(0, 0, 255), 
    INDIGO(70, 0, 135), 
    VIOLET(238, 130, 220);

    fun rgb() = (r * 256 + g) * 256 + b
}
 

使用 "when” 处理枚举类:

1.when是一个有返回值的表达式,因此,作为表达式函数体,它可以去掉花括号和return语句,并省略返回类型的声明。

2.when和Java中的switch语句类似,根据when中Color的值走到对应的分支,除此之外,我们可以把多个值用逗号间隔,合并到同一个分支

3.在 “when”结构中使用任意对象

4.对于不属于的分支,我们需要提供额外的else操作符

fun main(args: Array<String>) {
    println(getWarmth(Color.ORANGE))//warm
    println(getWarmth(Color.GREEN))//neutral

    println(mix(Color.BLUE, Color.YELLOW))//GREEN
}
​
enum class Color{
    RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
​
//when color匹配如下的一组
fun getWarmth(color: Color) = when(color){
    Color.RED, Color.ORANGE, Color.YELLOW ->"warm"
    Color.GREEN -> "neutral"
    Color.BLUE, Color.INDIGO, Color.VIOLET ->"cold"    
}
​
//在 “when”结构中使用任意对象
fun mix(c1: Color, c2: Color) = 
    when(setOf(c1, c2)){
        setOf(Color.RED, Color.YELLOW) -> Color.ORANGE
        setOf(Color.YELLOW, Color.BLUE) -> Color.GREEN
        setOf(Color.BLUE, Color.VIOLET) -> Color.INDIGO
        //对于不属于的分支,我们需要提供额外的else操作符
        else -> throw Exception("Dirty color")
}
 

类型智能转换:

1.在kotlin中,判断一个变量是否是某种类型需要使用is关键字,类似Java当中的instanceOf

2.在Java中,在检查完后,使用时还需要显式地加上类型转换。

3.在kotlin中,如果你检查过一个变量是某种类型,后面在使用的过程中,就不需要再转换它,可以把它当做你检查过的类型来使用。

4.智能转换,只在变量经过is检查且之后不再发生变化的情况下有效,当你对一个类的属性进行智能转换的时候,这个属性必须是一个val属性,而且不能有自定义的访问器,否则,每次对属性的访问是否都能返回同样的值将无从验证。

5.when,try catch代码块相关,代码块中的最后一个表达式就是结果

fun main(args: Array<String>) {
    println(cal(Sum( Sum(Num(2), Num(3)), Num(4) )))//9
}
​
interface Expr
class Num(val value: Int) : Expr
​
class Sum(val left: Expr, val right: Expr) : Expr
​
fun cal(expr: Expr): Int = 
    when(expr){
        is Num -> expr.value//value值是否是Num类型,是的话下面直接用
        is Sum -> cal(expr.left) + cal(expr.right)//代码块中,最后一个表达式,即结果
        else -> 0
    }
 

在Kotlin中,使用了 "区间" 替代常见的循环用法:

用法:两个值之间的间隔,这两个值通常是数字,一个起始值,一个结束值,使用..运算符来表示区间,而结束值始终是区间的一部分。

fun main(args: Array<String>) {
    println(forFunc(1, 5))//Num=1 Num=2 Num=3 Num=4 Num=5
    println(forFunc2(1, 10))//Num=10 Num=8 Num=6 Num=4 Num=2
    println(forFunc3(1, 5))//Num=1 Num=2 Num=3 Num=4
}
​
//遍历区间的每一个元素,默认步长是1
fun forFunc(startValue: Int, endValue: Int){
    for(i in startValue..endValue){
        println("Num=$i")
    }
}
​
//downTo用于递减到指定的值
fun forFunc2(startValue: Int, endValue: Int){
    for(i in endValue downTo startValue step 2){
        println("Num=$i")
    }
}
​
//使用until则可以使迭代不包含指定的结束值
fun forFunc3(startValue: Int, endValue: Int){
    for(i in startValue until endValue){
        println("Num=$i")
    }
}
 

迭代map使用:(Beta)

fun main(args: Array<String>) {

    val binaryReps = TreeMap<Char, String>()

    for(c in 'A'..'F'){
        val binary = Integer.toBinaryString(c.toInt())
        binaryReps[c] = binary//下标变成了key值
    }

    for((letter, binary) in binaryReps){
        //允许展开迭代中的集合的元素,把展开的结果存储到了两个独立的变量中:letter是键、binary是值
        println("$letter = $binary")
    }

}
 

使用 in 运算符判断值是否在区间中,反之逆运算 !in:

fun main(args: Array<String>) {
    println(isLetter('q'))//true
    println(isNotDigit('x'))//true
}
​
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
fun isNotDigit(c: Char) = c !in '0'..'9'
 

kotlin 中的异常:(Beta)

1.kotlin不区分受检异常和未受检异常,不必指定函数抛出的异常,而且可以处理也可以不处理异常。

2.kotlin的throws子句没有出现在代码中

3.kotlin的throw结构是一个表达式时,能作为另一个表达式的一部分使用。

fun main(args: Array<String>) {

    val reader = BufferedReader(StringReader("234"))
    println(readNumber(reader))
}
​
fun readNumber(reader: BufferedReader): Int?{
    try{
        val line = reader.readLine()
        return Integer.parseInt(line)
    }catch (e: NumberFormatException){
        return null
    }finally{
        reader.close()
    }
}
 

扩展函数:

1.Kotlin会把扩展函数当做静态函数来对待,因此扩展函数不存在重写。

2.改变字符串内的字符,使用单引号' ',因为外层已经用了双引号。

fun main(args: Array<String>) {
    println("Hello, world!".lastChar())//!

    println("Kotlin".lastChar)//n
    val sb = StringBuilder("Kotlin?")
    sb.lastChar = '!'
    println(sb)//Kotlin!
}
​
//拓展方法
fun String.lastChar(): Char = this.get(this.length -1)
​
//拓展属性
val String.lastChar: Char 
    get() = get(length - 1)
var StringBuilder.lastChar: Char
    get() = get(length - 1)
    set(value: Char){
        this.setCharAt(length - 1, value)
    }
 

可变参数的相关处理:

1.可变参数,使用关键字 vararg

2.参数打包成一个数组,在传入参时需要通过 * 操作符进行解包

fun main(args: Array<String>) {
    varargFunc(1, 2, 3, 4, 5, 6)//多个单独参数

    val intArray = intArrayOf(1, 2, 3, 4, 5)
    varargFunc(*intArray)//参数装成数组,需要*解包
}
​
fun varargFunc(vararg ints:Int){
    println(ints.javaClass)//class [I
    for(i in ints){
        println("var=$i")//var=1 var=2 var=3 var=4 var=5 var=6
    }
}
 

中缀调用:

1.无论是普通的函数还是扩展函数,要允许使用中缀符号调用函数,需要使用infix修饰符来标记它

2.中缀调用 不是特殊的内置结构,而是一种特殊的函数调用。在中缀调用中,没有添加额外的分隔符,函数名称是直接放在目标对象名称和参数之间。

3.Any是Kotlin中所有类的父类,和Java中的Object相同

fun main(args: Array<String>) {
    val married: Person = "haha" create true
    println("Name=${married.name}, isMarried=${married.isMarried}")//Name=haha, isMarried=true
}
​
class Person(val name: Any, val isMarried: Any)
​
infix fun Any.create(isMarried: Any) = Person(this, isMarried)
 

字符串进行分割:

1.在kotlin中可以使用Regex类型的重载函数对字符串进行分割

2.如下\\.转义,而|是或的意思

例子1:

fun main(args: Array<String>) {
    println("haha.hehe.AA|BB-CC-DD".split("\\.|-".toRegex()))//[haha, hehe, AA|BB, CC, DD]
}
 

例子2:

需求:通过这个字符串获取到chapter.adoc的目录、文件名和扩展名1

fun main(args: Array<String>) {
    parsePath("/Users/yole/kotlin-book/chapter.adoc")
}
​
//使用扩展函数实现
// fun parsePath(path: String){
//     val directory = path.substringBeforeLast("/")
//     val fullName = path.substringAfterLast("/")
//     val fileName = fullName.substringBeforeLast(".")
//     val extension = fullName.substringAfterLast(".")
//     //Dir:/Users/yole/kotlin-book,name:chapter,ext:adoc
//     println("Dir:$directory,name:$fileName,ext:$extension")
// }
​
//使用正则表达式
fun parsePath(path: String){
    //"/Users/yole/kotlin-book/chapter.adoc"
    //                    (.+)/(.+)   .(.+)
    //这个正则表达式将一个路径分为三个由斜线和点分隔的组
    val regex = """(.+)/(.+)\.(.+)""".toRegex()
    val matchResult = regex.matchEntire(path)
    if(matchResult != null){
        val (directory, fileName, extension) = matchResult.destructured
        //Dir:/Users/yole/kotlin-book,name:chapter,ext:adoc
        println("Dir:$directory,name:$fileName,ext:$extension")
    }
}
 

局部函数使用:

fun main(args: Array<String>) {
    saveUser(User(1, "", ""))
}
​
fun saveUser(user: User){
    //局部函数
    fun validate(value: String, fieldName: String){
        if(value.isEmpty()){
            throw IllegalArgumentException("Can't save user ${user.id}:"+"empty $fieldName")
        }
    }
    validate(user.name, "Name")
    validate(user.address, "Address")
}
​
class User(val id: Int, val name: String, val address: String)
异常打印:



Exception in thread "main" java.lang.IllegalArgumentException: Can't save user 1:empty Name
    at ch02.ex1_1_HelloWorld._1_HelloWorldKt$saveUser$1.invoke(1_HelloWorld.kt:11)
    at ch02.ex1_1_HelloWorld._1_HelloWorldKt.saveUser(1_HelloWorld.kt:14)
    at ch02.ex1_1_HelloWorld._1_HelloWorldKt.main(1_HelloWorld.kt:5)
 

kotlin第二部分:

接口相关:

1.一个简单的Kotlin接口使用 interface 关键字来声明,所有实现这个接口的非抽象类都需要实现接口中定义的抽象方法。

2.Kotlin在类名后面使用 冒号 代替了Java中的extends和implements关键字,一个类可以实现多个接口,但是只能继承一个类。

3.override修饰符用来标注被重写的父类或者接口的方法和属性,并且是 强制要求的。

fun main(args: Array<String>) {
    Button().click()//Button()对象实例
    Button().showOff()//I'm clickable!
}
​
interface Clickable{
    fun click()
    //默认的实现方法
    fun showOff() = println("I'm clickable!")
}
​
class Button : Clickable{
    override fun click() = println("I was clicked")
}
 

4.如果一个类实现了两个接口,而这两个接口定义了相同的方法,并且都提供了该方法的默认实现,那么该类必须显示实现该方法,否则会在编译时报错;

另外,调用父类或接口的方法,可以使用与Java相同的关键字 super,并在后面的尖括号中指明父类的名字,最后是调用的方法名。

fun main(args: Array<String>) {
    Button().click()//Button()对象实例
    Button().showOff()//I'm focusable!
}
​
interface Clickable{
    fun click()
    fun showOff() = println("I'm clickable!")//相同方法名
}
​
interface Focusable{
    fun setFocus(b: Boolean) = println("I  ${if (b) "got" else "lost"} focus.")
    fun showOff() = println("I'm focusable!")//相同方法名
}
​
​
class Button : Clickable, Focusable{
    override fun click() = println("I was clicked")

    override fun showOff(){
        //通过显示的实现方法调用来区分实现多个接口的相同方法
        //super<Clickable>.showOff()
        super<Focusable>.showOff()
    }

}
 

访问性修饰符:open、final、abstract

1.在Kotlin中,类和方法默认都是final的,如果想允许创建一个类的子类,需要使用open修饰符来标示这个类,此外还需要给每一个允许被重写的属性或方法添加open修饰符

2.抽象类中的抽象函数:没有函数体就默认是abstract的,不一定要加上关键字,其访问性始终是open的。

3.抽象类中的非抽象函数:默认是final的,如果需要重写,那么需要加上open修饰符。

4.open、final和abstract这三个访问修饰符都 只适用于类,不能用在接口当中。

5.被重写方法必须加上override修饰符。

可见性修饰符:

public 所有地方可见;internal 模块中可见;protected 子类中可见;private 类中可见

1.Java和Kotlin在可见性上的区别包括以下几点:

在Java中默认的可见性是包私有的,而在Kotlin中,默认的可见性是public的。Kotlin用internal作为包可见的替代方案,它表示“只在模块内部可见”。

2.Kotlin允许在顶层声明中使用private可见性,包括类、函数和属性,这些声明就只在声明它们的文件中可见,这是隐藏子系统实现细节的非常有用的方式。

3.类的扩展函数不能访问它的private和protected成员。

4.Kotlin中,一个外部类不能看到其内部类中的private成员。

 

内部类和嵌套类:

1.kotlin中是嵌套类,是一个静态内部类,不持有外部类引用,类似java中的内部类

interface State: Serializable
interface View{
    fun getCurrentState(): State
    fun restoreState(state: State){}
}
​
class Button: View{
    override fun getCurrentState()
    override fun restoreState(state: State){}

    //kotlin中默认是嵌套类,不持有外部类引用,类似java中的内部类
    class ButtonState : State{}
}
 

2.把嵌套类变成内部类需要使用inner修饰符,并且访问外部类时需要this@{外部类名}

class Outer{
    //把嵌套类变成内部类需要使用inner修饰符,并且访问外部类时需要this@{外部类名}
    inner class Inner{
        fun getOuterReference(): Outer = this@Outer
    }
}
 

密封类:定义受限的类继承结构,使用sealed修饰符,对可能创建的子类做出严格的限制,所有的直接子类必须嵌套在父类中。

fun main(args: Array<String>) {
    println(eval(Expr.Sum( Expr.Sum(Expr.Num(2), Expr.Num(3)), Expr.Num(4) )))//9
}
​
sealed class Expr{
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
}
​
fun eval(e: Expr): Int = 
    when(e){
        is Expr.Num -> e.value//value值是否是Num类型,是的话下面直接用
        is Expr.Sum -> eval(e.left) + eval(e.right)//代码块中,最后一个表达式,即结果
    }
 

这时候,我们在when表达式中已经处理了所有Expr的子类,就不再需要提供默认的分支(else分支),假如这时候我们给Expr添加一个新的子类Multi,但是不修改when中的逻辑,那么就会导致编译失败:

解决:1.when中加上该分支 2.when加上默认的else分支

 

fun main(args: Array<String>) {
    //println(eval(Expr.Sum( Expr.Sum(Expr.Num(2), Expr.Num(3)), Expr.Num(4) )))//9

    println(eval(Expr.Multi( Expr.Num(2), Expr.Num(3) )))//6
}
​
sealed class Expr{
    class Num(val value: Int) : Expr()
    class Sum(val left: Expr, val right: Expr) : Expr()
    class Multi(val left: Expr, val right: Expr) : Expr()
}
​
fun eval(e: Expr): Int = 
    when(e){
        is Expr.Num -> e.value//value值是否是Num类型,是的话下面直接用
        is Expr.Sum -> eval(e.left) + eval(e.right)//代码块中,最后一个表达式,即结果
        is Expr.Multi -> eval(e.left) * eval(e.right)//代码块中,最后一个表达式,即结果
    }

 

构造方法:

kotlin将构造方法分为两类:

(java中则可以在类中声明一个或多个构造方法)

1.主构造方法:主要而简洁的初始化类的方法,并且在类体外部声明。

2.从构造方法:在 类体内部声明。

3.红色部分是主构造方法,简化写法:class User(val nickname: String)

(主构造方法:定义参数及参数类型属性)

完整写法:

class User constructor(_nickname: String){
    val nickname: String

    init{
        nickname = _nickname
    }
}
 

4.子类继承父类,并传递参数

fun main(args: Array<String>) {
    val tUser = TwitterUser("haha")
    println("Name=${tUser.nickname}")//Name=haha
}
​
open class User(val nickname: String)
​
class TwitterUser(nickname: String) : User(nickname)
 

5.kotlin中假如一个类没有声明任何的构造方法,将会生成一个不做任何事的默认构造方法,如果有子类继承了它,那么必须显示地调用父类的构造方法

6.定义从构造方法:constructor

fun main(args: Array<String>) {
    val view = View()
    println("Name=${view.ctx.name}, attr=${view.attr.name}")//Name=I am default, attr=I am default

    val view2 = View(Context("hahahehe"))
    println("Name=${view2.ctx.name}, attr=${view2.attr.name}")//Name=hahahehe, attr=I am default
}
​
class Context(val name: String)
class Attribute(val name: String)
​
open class View{
    var ctx = Context("I am default")
    var attr = Attribute("I am default")


    constructor(){
    }

    constructor(ctx: Context){
        this.ctx = ctx
    }

    constructor(ctx: Context, attr: Attribute){
        this.ctx = ctx
        this.attr = attr
    }

}
 

7.子类调用父类的从构造方法:super

8.子类调用自己的另一个构造方法:this

 

实现在接口中声明的属性:

fun getFacebookName(accountId: Int) = "fb:$accountId"
​
interface User{
    val nickname: String
}
​
//直接在主构造方法中声明了这个属性,这个属性实现了来自于User的抽象属性,所以要标记为override。
class PrivateUser(override val nickname: String) : User
​
//通过一个自定义的getter实现,这个属性没有一个支持字段来存储它的值,它只有一个getter在每次调用时从email中得到昵称。
class SubscribingUser(val email: Strng) : User{
    override val nickname: String
        get() = email.substringBefore('@')
}
​
//在初始化时,将nickname属性与值关联。
class FacebookUser(val accountId: Int) : User{
    override val nickname = getFacebookName(accountId)
}
 

第三部分:

data关键字:

1.data关键字自动生成,equals、hashCode、toString方法

2.equals方法会检测所有的属性的值是否相等

3.hashCode方法会返回一个根据所有属性生成的哈希值

4.使用copy方法,副本不会影响到原始实例内容

(在设计数据类时,应当尽量只使用只读的属性,让数据类的实例不可变,因为如果不这样,被用作键的对象在加入HashMap或者类似容器后被修改了,容器会进入一种无效的状态。)

fun main(args: Array<String>) {
    val bob = Client("Bob", 973293)
    //使用自动生成的toString
    println(bob)//Client(name=Bob, postalCode=973293)

    val bob2 = Client("Bob", 973293)
    //使用自动生成的equals
    println(bob == bob2)//true
​
    val hashSet = hashSetOf<Client>()
    hashSet.add(bob)
    //使用自动生成的hashCode
    println(hashSet.contains(bob2))//true

    //使用copy方法,副本不会影响到原始实例内容
    println(bob.copy(postalCode = 382555))//Client(name=Bob, postalCode=382555)
}
​
data class Client(val name: String, val postalCode: Int)
 

by关键字:将接口的实现委托到另一个对象

fun main(args: Array<String>) {
    val cset = CountingSet<Int>()
    cset.addAll(listOf(1, 2, 3))
    println("${cset.objectsAdded} objects were added, ${cset.size} remain")//3 objects were added, 3 remain
}
​
class CountingSet<T>(val innerSet: MutableCollection<T> = HashSet<T>()) : MutableCollection<T> by innerSet{
    var objectsAdded = 0
    override fun add(element: T): Boolean{
        objectsAdded++
        return innerSet.add(element)
    }

    override fun addAll(c: Collection<T>): Boolean{
        objectsAdded += c.size
        println("$objectsAdded,${c.size}")//3,3
        return innerSet.addAll(c)
    }
}
 

object关键字:定义一个类并同时创建一个实例

1.对象声明:是定义单例的一种方式

1)一个对象声明可以包含属性、方法、初始化语句块等的声明,但是不允许声明构造方法,这是因为对象在定义的时候就已经创建了,不需要在其他地方调用构造方法。

2)对象声明允许使用对象名 . 字符的方式来调用方法和访问属性。

3)可以在类中使用对象声明

fun main(args: Array<String>) {
    println("Name=${Person.name}, Age=${Person.age}")//Name=Default Name, Age=15
}
​
//单例
object Person{
    var name : String = "Default Name"
    var age : Int = 15
}
 

2.伴生对象:可以持有工厂方法和其它与这个类相关,但在调用时并不依赖类实例的方法,它们的成员可以通过类名来访问。

fun main(args: Array<String>) {
    Outer.innerMethod()//类名直接调用
}
​
class Outer{
    //companion object关键字,不需要指定类名,其他地方可以直接类名调用
    companion object{
        fun innerMethod(){
            println("innerMethod is called")
        }
    }
}
 

3.对象表达式:用来替代Java的匿名内部类。(beta)

fun main(args: Array<String>) {
    val button = Button()
    //object代替匿名内部类
    button.setOnClickListener(
        object : OnClickListener){
        override fun onClick() = println("Button is clicked")
    }
    button.click()
}
​
interface OnClickListener{
    fun onClick()
}
​
class Button{
    var listener : OnClickListener? = null
    fun setOnClickListener(listener : OnClickListener){
        this.listener = listener
    }
    fun click(){
        listener?.onClick()
    }
}
 

在Java中使用Kotlin对象:

如果要在Java中使用Kotlin中的声明对象,可以通过访问静态的INSTANCE字段:

Kotlin中的对象声明:

Java中调用方式:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值