ADeveloperH Blog

Meet a better self !

Android 周边技术分享


Kotlin(一)

参考资料

Kotlin官网

Kotlin In Action 中文版GitBook

Kotlin for android Developers 中文翻译

Kotlin 语言参考文档中文版

kotlin 的干货搜集 ,不能错过

使用 Kotlin 进行 Android 开发

环境搭建

使用 IDEA 开发:

Kotlin Primer·第一章·启程

1 Kotlin 基础语法

1.1 变量声明、函数声明

package chapter1

/**
 * 变量名在前,变量类型在后,如果类型能推断可以不用写类型
 */

//var 表示变量
var age: Int = 28

//val 表示不可变的变量。注意:不是常量
val name: String = "huangjian"

//如果类型可以推断出来,可以不用写类型
var sex = "male"


var str1: String = "test"
//String 和 String? 是两种不同的类型。是不能互相赋值的
//String 类型是不可为空的,如果设置为空编译器会报错
//String? 是可以为空也可以不为空的类型
var str2: String? = "test2"

fun main(args: Array<String>) {
    //不能直接赋值,因为是两种不同的类型,如果能保证 str2 不为空,可以加  !! 进行强转赋值
    str1 = str2!!

    //可以直接赋值,因为 String? 表示可以为空和不可为空的类型,其中包含 String
    str2 = str1

    //入参不能是 String? 类型
//    pringLn(str2)

    pringLn(str1)
}


/**
 * 函数以关键字 fun 标识
 * 1、函数参数声明和变量声明一致
 * 2、函数返回值在函数体后声明
 */
fun pringLn(arg: String): String {
    //Kotlin 的模板语法:可以使用 $ 在字符串中引用变量
    println("字符串为:$arg")
    return arg
}



1.2 Kotlin 和 Java 互调

Idea 定义 Java 代码生成 main 函数模板:
intellij idea优化_生成main方法_自动补全代码_live template


JavaMain.java 文件

package chapter1.class2;

public class JavaMain {

    //测试与 Kotlin 关键字冲突问题
    public static String in = "in";

    public static void main(String[] args){
        //调用 Kotlin 中的函数,直接通过 “文件名Kt.方法名”调用
        //Util 中声明的方法、变量 ,最终都会被编译成 public
        UtilKt.echo(UtilKt.getName());

        //调用匿名内部类
        Test.INSTANCE.sayMsg("hello from main");

    }
}


Util.kt 文件

package chapter1.class2

import kotlin.reflect.KClass

//最终被编译成 public 变量
var name = "huangjian"

/**
 * Kotlin 的函数直接可以写在文件中,不用写在类中
 * 最终被编译成 public 的方法,在 Java 类中可以直接通过文件名调用该方法
 */
fun echo(name: String) {
    println("$name")
}

fun main(args: Array<String>) {
    //Kotlin 中可以直接调用匿名类的方法
    Test.sayMsg("hello from Kotlin")
}

/**
 * 匿名内部类的写法
 */
object Test {
    fun sayMsg(msg: String) {
        println(msg)

        //java 的 class 对象传入方式
        testClass(JavaMain::class.java)

        //kotlin 的 class 对象传入方式
        testClass(KotlinMain::class)

        //kotlin  Java 变量,变量名与 kotlin 的关键字冲突时使用 ``
        println(JavaMain.`in`)
    }
}

/**
 * 测试入参为 Java 的 Class
 */
fun testClass(clazz: Class<JavaMain>) {
    println(clazz.simpleName)
}

/**
 * 测试入参为 Kotlin 的 Class。Kotlin 的 Class 为 KClass
 */
fun testClass(clazz: KClass<KotlinMain>) {
    println(clazz.simpleName)
}

KotlinMain.kt 文件

package chapter1.class2

class KotlinMain


1.3 Kotlin 与 Java 的不同

Kotlin 没有封装类,所有的变量最终都被解释为 Java 中的基本数据类型,而不是封装类型


TestInterface.java 文件

package chapter1.class3;

public interface TestInterface {
    //入参为基本数据类型
    void putNumber(int number);

    //入参为封装类型
    void putNumber(Integer number);
}

Test.java 文件

package chapter1.class3;

public class Test implements TestInterface {
    @Override
    public void putNumber(int number) {
        System.out.println("int 类型的调用");
    }

    @Override
    public void putNumber(Integer number) {
        System.out.println("Integer 类型的调用");
    }
}

Test.kt 文件

package chapter1.class3

fun main(args: Array<String>) {
    //调用 Java 中 Test 类的方法,调用的是入参为 int 类型的方法,不是入参为 Integer 的方法
    //如果想要调用 入参为 Integer 类型的方法,需要使用反射才能调用
    Test().putNumber(123)//输出为“int 类型的调用”
}


class TestInKotlin : TestInterface {
    override fun putNumber(number: Int) {
    }

    //编译器会提示没有 Integer 这个类型的
//    override fun putNumber(number: Int?) {
//    }

}

Kotlin 类型没有空值敏感


Test.java 文件

package chapter1.class3;

public class Test{
    //声明静态方法
    public static String fromat(String string) {
        return string.isEmpty() ? null : string;
    }
}


Test.kt 文件

package chapter1.class3

fun main(args: Array<String>) {
    function("")
}

fun function(str: String) {
    //编译器类型推断为 String! ,这个类型是编译器临时使用的,不能手动的声明
    val fmat1 = Test.fromat(str)
    //会报错,因为范围值为 null 不是 String 类型
//    val fmat2: String = Test.fromat(str)
    val fmat3: String? = Test.fromat(str)

    //会报空指针错误,因为 fmat1 可能为 null
//    println(fmat1.length)

    //Kotlin 的特性,空安全
    println(fmat3?.length)//输出为 null
}

Kotlin 没有静态变量和静态方法,声明静态方法和静态变量的方法如下:


Test.kt 文件

package chapter1.class3

object KotlinTest {
    //使用 @JvmStatic 注解,将 Kotlin 中方法声明为静态变量
    @JvmStatic
    val str: String = "str from KotlinTest "

    //使用 @JvmStatic 注解,将 Kotlin 中方法声明为静态方法,在 Java 可以直接通过“类名.方法名”调用
    @JvmStatic
    fun print(str: String) {
        println(str)
    }
}


Test.java 文件

package chapter1.class3;

public class Test {
    public static void main(String[] args) {
        //调用 Kotlin 中的静态方法和静态变量
        KotlinTest.print(KotlinTest.getStr());
    }
}


1.4 Kotlin 中的函数

函数和方法的区别(Java 中只有方法,没有函数):

方法(method)和函数(function)有什么区别?

函数和方法的区别


Kotlin.kt 文件

package chapter1.class4

fun echo(name: String) {
    println("$name")
}

/**
 * 带默认值的函数,可大大减少方法重载的数量
 */
fun echo2(name: String = "huangjian") {
    println(name)
}

/**
 * 函数体只有一个语句时,可以直接赋值给函数
 */
fun echo3(name: String) = println("$name")


/**
 * 函数嵌套。不建议使用
 * 递归调用时,或者不希望函数被外部访问时可以使用内部函数
 */
fun function() {
    val str = "hello world"
    fun say(count: Int = 10) {
        println(str + count)
        if (count > 1) {
            say(count - 1)
        }
    }
    say()
}

fun main(args: Array<String>) {
    echo("hello")
    echo2()
    echo2("hello2")
    echo3("hello3")

    function()
}

Kotlin 中的扩展函数,用于一些第三方的 SDK,或者不可更改的类中新增方法时,如下:


Test.kt 文件

package chapter1.class5

import java.io.File
import java.nio.charset.Charset

/**
 * Kotlin 独特的扩展函数
 * 静态的给类添加成员变量和成员方法
 */
fun File.readText(charset: Charset = Charsets.UTF_8): String = readBytes().toString(charset)

fun main(args: Array<String>) {
    val file = File("KotlinIDEA.iml")
    println(file.readText())
}

JavaMain.java 文件

package chapter1.class5;

import kotlin.text.Charsets;
import java.io.File;

public class JavaMain {
    public static void main(String[] args){
        File file = new File("KotlinIDEA.iml");

        //Java 中调用 Kotlin 中的扩展函数,注意需要将扩展的对象作为第一个入参传入,而且没有默认的入参值
        String result = TestKt.readText(file, Charsets.UTF_8);
        System.out.println(result);
    }
}


Kotlin 扩展函数静态解析,没有运行时多态


Test.kt 文件

package chapter1.class5


/**
 * Kotlin 中的类默认加上 final 关键字
 * open 表示这个类不是 final 的
 */
open class Animal

class Dog : Animal()

//给 Animal 新增静态方法
fun Animal.name() = "animal"
//给 Dog 新增静态方法
fun Dog.name() = "dog"

//给 Animal 新增静态方法
fun Animal.printName(animal: Animal) {
    println(animal.name())
}
//给 Dog 新增静态方法
fun Dog.printName2(animal: Animal) {
    println(animal.name())
}
//给 Dog 新增静态方法
fun Dog.printName3(dog: Dog) {
    println(dog.name())
}

fun main(args: Array<String>) {
    /**
     * 扩展函数静态解析,没有运行时多态
     */
    Dog().printName(Dog())//输出“animal”
    Dog().printName2(Dog())//输出“animal”
    Dog().printName3(Dog())//输出“dog”
}

1.5 Kotlin 中 Lambda

java 8 中的 Lambda 表达式:

JavaMain.java 文件

package chapter1.class7;

public class JavaMain {

    public static void main(String[] args){
        System.out.println(Thread.currentThread().getName());//main
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());//Thread-0
            }
        });
        thread.start();


        //java 8 Lambda 表达式
        Thread thread1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName());//Thread-1
        });
        thread1.start();
    }
}


Kotlin 中的 Lambda:


KotlinMain.kt 文件

package chapter1.class7

fun main(args: Array<String>) {
    testLambda()
    echo("hello")

    lambdaA(1, 1, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1)

    lambdaB(1, 1, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 1,
            1, 1, 1, 1, 1,
            1, 1, 1, 1, 1, 1)
}

fun testLambda() {

    Thread({ -> println(Thread.currentThread().name) }).start()

    //Lambda 没有参数可以省略箭头
    Thread({ println(Thread.currentThread().name) }).start()

    //Lambda 是函数的最后一个参数,可以将大括号放在小括号外边
    Thread() { println(Thread.currentThread().name) }.start()

    //函数只有一个参数且是 Lambda 可以省略小括号
    Thread { println(Thread.currentThread().name) }.start()

}

//Lambda 闭包声明
val echo = { name: String -> println(name) }

val lambdaA = { a: Int, b: Int, c: Int, d: Int, e: Int,
                f: Int, g: Int, h: Int, i: Int, j: Int,
                k: Int, l: Int, m: Int, n: Int, o: Int,
                p: Int, q: Int, r: Int, s: Int, t: Int,
                u: Int, v: Int ->
    println("huangjian")
}

//Lambda 闭包最多只有22个参数,否则会报错:java.lang.NoClassDefFoundError: kotlin/Function23
//解决方案:使用 Java 代码手动定义 Function23。需要在 kotlin 包下使用 java 代码手动实现
//使用 kotlin 实现会报错:Error:(1, 1) Kotlin: Only the Kotlin standard library is allowed to use the 'kotlin' package
val lambdaB = { a: Int, b: Int, c: Int, d: Int, e: Int,
                f: Int, g: Int, h: Int, i: Int, j: Int,
                k: Int, l: Int, m: Int, n: Int, o: Int,
                p: Int, q: Int, r: Int, s: Int, t: Int,
                u: Int, v: Int, w: Int ->
    println("huangjian")
}


Function23.java 文件

package kotlin;

/**
 * A function that takes 23 arguments.
 */
public interface Function23<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11,
        P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, R> extends Function<R> {
    R invoke(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9,
             P10 p10, P11 p11, P12 p12, P13 p13, P14 p14, P15 p15, P16 p16,
             P17 p17, P18 p18, P19 p19, P20 p20, P21 p21, P22 p22, P23 p23);
}

高阶函数的使用:


KotlinMain.kt 文件

package chapter1.class8

fun main(args: Array<String>) {
    //最后一个参数为 Lambda 可以将大括号放到小括号的拿出来
    onlyIf(true) {
        println("hello 高阶函数")
    }

    //最后一个参数需要传入为函数的声明
    onlyIf(true, function)

    val button: View = View()
    button.id = 123123

    button.setOnClick(View.OnClickListener { println("开始设置 listener1") })
    button.setOnClick2 { view: View? ->
        println(view?.id)
        println("开始设置 listener2")
    }
    button.setOnClick2 {
        //Lambda 表达式单个参数会隐式声明为 it 。可以不用声明唯一的参数并忽略 ->,通过 it 来调用
        println(it?.id)
        println("开始设置 listener2")
    }

    button.setOnClick3 {
        println(it?.id)
        println("开始设置 listener3")
    }
}


/**
 * 函数的参数是函数(Lambda)
 *  函数最后一个参数:参数为空 返回值为 Unit 的 Lambda
 *  Unit 是一个没有返回值的函数默认会返回的类型,一般可以省略
 *  这里 Unit 不能省略:https://www.kotlincn.net/docs/reference/lambdas.html#函数类型
 */
/**
 *  Kotlin 中,Lambda 会被编译成一个匿名对象
 * 使用 inline 关键字(内联)可以优化,编译时不会生成额外的对象,调用处直接回拆解方法的调用为语句的调用
 * 从而可以减少创建不必要的对象(以通过源码查看调用处)
 */
inline fun onlyIf(isDebug: Boolean, block: () -> Unit) {
    if (isDebug) block()
}

//声明一个 Runnable 对象
val runnable = Runnable { println("Runnable::run") }

//函数是“一等公民”,可以作为一个变量。声明一个函数:参数为空,返回值为 Unit
// 引用函数声明:对象::函数名,可以作为参数传递给高阶函数 。不能是 对象.函数 ,这样实际调用的是函数的返回值
val function: () -> Unit = runnable::run


/**
 * 模拟设置 View 的 listener
 * 参数为:View.OnClickListener 对象
 */
fun View.setOnClick(listener: View.OnClickListener) {
    setOnClickListener(listener)
}

/**
 * 模拟设置 View 的 listener
 * 参数为: Lambda 表达式。
 */
fun View.setOnClick2(listener: (view: View?) -> Unit) {
    setOnClickListener(listener)
}

/**
 * 模拟设置 View 的 listener
 * 参数为: Lambda 表达式 .可以省略闭包参数名,直接声明类型即可
 */
fun View.setOnClick3(listener: (View?) -> Unit) {
    setOnClickListener(listener)
}


View.java 文件

package chapter1.class7;

import org.jetbrains.annotations.Nullable;

public class View {

    /**
     * Register a callback to be invoked when this view is clicked. If this view is not
     * clickable, it becomes clickable.
     *
     * @param l The callback that will run
     */
    public void setOnClickListener(@Nullable OnClickListener l) {
        System.out.println("clicklistener 被调用了");
    }

    /**
     * Interface definition for a callback to be invoked when a view is clicked.
     */
    public interface OnClickListener {
        /**
         * Called when a view has been clicked.
         *
         * @param v The view that was clicked.
         */
        void onClick(View v);
    }
}

1.6 Kotlin 类相关知识

类与继承

1.7 Kotlin 伴生对象、单例相关

可见性修饰符:

可见性修饰符 internal 标识的是在模块内可见(在项目中创建的 Module)

可见性修饰符

伴生对象及单例的写法:

对象声明


KotlinMain.kt 文件

package chapter1.class10

fun main(args: Array<String>) {

    println(StringUtils.isEmpty("="))
    println(StringUtils2.isEmpty(""))

    Single.getInstance().testInstance()
}

//静态函数的第一种写法。
object StringUtils {
    @JvmStatic
    fun isEmpty(string: String?): Boolean {
        if (string == null) {
            return true
        } else {
            return "" == string
        }
    }
}

//静态函数的第二种写法
class StringUtils2 {
    //伴生对象。编译后的源码可知,会在 StringUtils2 的内部生成一个 Companion 静态类的对象。
    //因此 java 调用的方式是:StringUtils2.Companion.isEmpty("")
    companion object {
        fun isEmpty(string: String?): Boolean {
            if (string == null) {
                return true
            } else {
                return "" == string
            }
        }
    }
}

//单例模式:直接使用 object 或者 使用伴生对象
//伴生对象写法(推荐)
//需要私有化构造函数
class Single private constructor() {
    private object Holder {
        val instance = Single()
    }

    companion object {
        fun getInstance(): Single = Holder.instance
    }

    fun testInstance() {
        println("测试单例模式")
    }
}

JavaMain.java 文件

package chapter1.class10;

public class JavaMain {
    public static void main(String[] args) {
        System.out.println(StringUtils.isEmpty(""));
        test();
    }

    //java 调用 kotlin 伴生对象
    public static void test() {
        System.out.println(StringUtils2.Companion.isEmpty(""));
    }
}


1.8 动态代理 及 特殊类

Java 中动态代理:

Android公共技术点之四-Java动态代理

java静态代理和动态代理

Java三种代理模式:静态代理、动态代理和cglib代理

Android中动态代理的使用

动态代理实现类似 Retrofit 请求

Kotlin 中动态代理:

委托属性

委托

Animal.kt 文件
package chapter2.class11

interface Animal{
    fun bark()
}

class Dog : Animal {
    override fun bark() {
        println("狗叫")
    }
}

//Kotlin 动态代理会被转换成静态代理,比 Java(最终通过反射) 效率高
class Zoo(animal: Animal) : Animal by animal{
//    override fun bark() {
//        println("Zoo bark")
//    }
}

DataClass.kt 文件

package chapter2.class11

//数据类是 final 的,不能使用 open 修饰,不能被继承
//默认添加 getter/setter 方法,默认实现 toString 、equals、copy 等方法
//查看生成的源码可以了解更多
data class User(val id: Int, val name: String)

KotlinMain.kt 文件

package chapter2.class11

fun main(args: Array<String>) {

    Zoo(Dog()).bark()

    val user = User(3123, "huangjian")
    val user2 = User(3123, "huangjian")
    val user3 = user.copy()
    println(user.name)
    println(user.toString())
    println("user == user2:${user == user2}")
    println("user === user2: ${user === user2}")
    println("user == user3: ${user == user3}")
    println("user === user3: ${user === user3}")
}

JavaMain.java 文件
package chapter2.class11;

public class JavaMain {
    public static void main(String[] args){
        //Java 动态代理实现见 study.proxy 包 和 study.proxyretrofit 包下相关 demo
    }
}

SealedClass.kt 文件

package chapter2.class11

//密闭类:所有的子类都在一起声明
sealed class SuperCommand {
    object A : SuperCommand()
    object B : SuperCommand()
    object C : SuperCommand()
    object D : SuperCommand()
    //可对枚举类进行扩展
    class E(val id: Int) : SuperCommand()
}

2.1 Kotlin 中的解构特性

代码如下:


package chapter2.class13

fun main(args: Array<String>) {
    val user = User(27, "huangjian")
    //Kotlin  的解构特性。查看源码可以知道具体的实现逻辑
    val (age, name, nickName) = user
    println(age)
    println(name)
    println(nickName)


    val map = mapOf<String, String>("key1" to "value1", "key2" to "value2")
    //循环 map 是使用解构
    for ((key, value) in map) {
        println("$key ========= $value")
    }
}

class User(val age: Int, val name: String) {
    //operator 将一个函数标记为重载一个操作符或实现一个约定
    //方法名称必须以 component+数字 命名
    operator fun component1() = age

    operator fun component2() = name
    operator fun component3() = name
}

2.2 Kotlin 中的循环

代码如下:


KotlinMain.kt

package chapter2.class14

fun main(args: Array<String>) {

    //[1-10]
    for (i in 1..10) {
        println(i)
    }

    //[1-10) 也就是 [1-9]
    for (i in 1 until 10) {
        println(i)
    }

    //[10-1] 逆序输出
    for (i in 10 downTo 1) {
        println(i)
    }

    //步长为 2
    for (i in 1..10 step 2) {
        println(i)
    }

    //[0-9]高级函数。传入闭包,表示循环的次数,it 表示当前循环的 index
    repeat(10) { println(it)}

    val arrayList = arrayListOf<String>("a", "b", "c", "d")
    for (string in arrayList) {
        println(string)
    }

    arrayList.forEach { 
        println(it)
    }

    //使用解构获取。map 可以直接使用,list 需要调用 withIndex 函数
    for ((index, str) in arrayList.withIndex()) {
        println("第$index 个元素是 $str")
    }

    repeat(arrayList.size) {
        println("第 ${it + 1} 个元素是 ${arrayList.get(it)}")
    }
}


2.3 Kotlin 中作用域函数

代码如下:


KotlinMain.kt 文件

package chapter2.class16

data class User(var age: Int, var name: String)

fun main(args: Array<String>) {
    //作用域函数:Kotlin 内置的可对数据进行变换的函数,与集合的操作符类似。
    // 但是作用域函数可以应用于所的对象
    val user = User(27, "huangjian")

    //let :返回闭包执行结果,let 可以有闭包参数
    val letResult: String = user.let { user: User -> "let::${user.javaClass}" }
    //当闭包参数只有一个时可以省略,用 it 来引用
//    val letResult: String = user.let { "let::${it.javaClass}" }
    println(letResult)

    //run :返回闭包执行结果,run 不可以有闭包参数。
    // 使用 this 来表示当前调用的对象 user ,不能使用 it 代替
    val runResult: String = user.run { "run::${this.javaClass}" }
    println(runResult)

    //also :不返回闭包执行结果,also 可以有闭包参数。
    user.also { println("also::${it.javaClass}") }

    //apply :不返回闭包执行结果,apply 不可以有闭包参数
    user.apply { println("apply::${this.javaClass}") }

    // also 和 apply 返回值还是当前的对象,所以可以链式调用
    user.also {
        it.age = 18
    }.apply {
        println(this.toString())
    }.apply {
        this.name = "ADeveloperH"
    }.also {
        println(it.toString())
    }

    user.also {
        it.name = ""
    }
    //takeIf 的闭包返回一个判断结果,为 false 时表示 takeIf 函数会返回空。
    user.takeIf { it.name.length > 0 }?.also { println("姓名不为空") } ?: println("姓名为空")

    //takeUnless 与 takeIf 刚好相反,闭包判断结果为 true 时函数会返回空
    user.takeUnless { it.name.length > 0 }?.also { println("姓名为空") } ?: println("姓名不为空")

    //循环执行当前闭包
    repeat(5) {
        println(it)
    }
}


常用的操作符

元素操作符:

contains:判断是否有指定元素

elementAt:返回对应的元素,越界会抛 IndexOutOfBoundsException

firstOrNull:返回符合条件的第一个元素,没有返回 Null

lastOfNull:返回符合条件的最后一个元素,没有返回 Null

indexOf:返回指定元素的下标,没有返回 -1

singleOrNull:返回符合条件的单个元素,如果没有符合或者超过一个,返回 Null

判断类:

any:判断集合中是否有满足条件的元素

all:判断集合中的元素是否都满足条件

none:判断集合中是否都不满足条件,是返回 true

count:查询集合中满足条件的元素个数

reduce:从第一项到最后一项进行累计

2.4 Kotlin 中自定义中缀表达式

代码如下:


KotlinMain.kt 文件

package chapter2.class17

fun main(args: Array<String>) {

    //运算符重载:例如 .. 使用 operator 声明
    // 中缀表达式:例如 step 使用 infix 声明
    for (i in 1..100 step 2) {
    }

    println(5 VS 6)
    println(7 VS 6)

    //中缀表达式也可以这样通过正常的函数调用一样去调用
    println(7.VS(7))
}

sealed class CompareResult {
    object More : CompareResult() {
        override fun toString(): String {
            return "大于"
        }
    }

    object Less : CompareResult() {
        override fun toString(): String {
            return "小于"
        }
    }

    object Equal : CompareResult() {
        override fun toString(): String {
            return "等于"
        }
    }
}

//自定义中缀表达式。
// 扩展函数,Int 为函数的函数接收者
infix fun Int.VS(num: Int): CompareResult =
        if (this < num) {
            CompareResult.Less
        } else if (this > num) {
            CompareResult.More
        } else {
            CompareResult.Equal
        }

2.5 Kotlin 中的特殊符号

代码如下:


KotlinMain.kt 文件

package chapter2.class18

fun main(args: Array<String>) {
    `23`()
    ` `()

    val string1 = "string"
    val string2 = String("string".toByteArray())


    //类似于 Java 中的 equals 方法。判断的是值
    println(string1 == string2)
    //类似于 Java 中的 == 。判断的是引用
    println(string1 === string2)

    //相当于直接使用 String
    val typealiasString = TypealiasString("typealias".toByteArray())
    println(typealiasString)
}


//使用反引号来设置函数名为数字(Kotlin 中是不能以数字为函数名的)
//Java 的语法不支持调用该函数。可以通过这种方式设置该函数只在 Kotlin 中使用
fun `23`() {
    println("fun 数字函数名")
}

fun ` `() {
    println("fun 空格函数名")
}

//相当于给 String 起别称。Kotlin 中有很多,例如 TypeAliases.kt 中相关的类
//用于跨平台的兼容性,可以实现映射
public typealias TypealiasString = java.lang.String

2.6 kotlin 中 val 和 var

代码如下:


package chapter2.class22

import java.util.*

fun main(args: Array<String>) {

    val hello = Hello()
    println(hello.string)
    println(hello.string2)

    var person = Person(1991)
    println(person.age)
    person.oneYearsLetter()
    println(person.age)

    println(s)
    println(A.s)
    println(B.s)
}


class Hello {
    //var 变量可以有 get / set 方法
    var string: String? = null
            //get 和 set 方法不能直接使用 string(直接使用相当于调用 get 方法了),需要使用 field ,否则会出现循环引用堆栈溢出
        get() {
            return field + "hello"
        }
        set(value) {
            field = value + "set"
        }


    //val 不可以有 set 方法,是不可变量不能再次赋值,但是可以通过重写 get 方法来改变它的值,但是 val 不是常量
    val string2: String? = null
        get() {
            return field + "hello"
        }
}

class Person(var birthYear: Int) {
    val age: Int
        get() {
            return Calendar.getInstance().get(Calendar.YEAR) - birthYear
        }

    fun oneYearsLetter() {
        birthYear--
    }
}


//const 只能修辞 top-level 变量,或 object / companion object 中的属性。不能有 get / set 方法
//const 变量的值必须在编译期间确定下来,所以它的类型只能是 String 或基本类型
const val s = 0

object A {
    const val s = 1
}

class B {
    companion object {
        const val s = 2
    }
}

最近的文章

Moco搭建模拟接口服务

参考资料如何快速搭建模拟接口服务Github代码Moco 框架以及其在 Web 集成测试的应用使用moco模拟http(s)请求【moco】https&证书1 简介Moco是一个简单搭建模拟服务器的程序库/工具,这个基于 Java 开发的开源项目已经在 Github 上获得了不少的关注。该项目的简介是这样描述自己的:Moco 是一个简单搭建 stub 的框架,主要用于测试和集成。这个框架的开发灵感来自 Mock 框架,如 Mockito 和 Playframework。为什么要开发...…

继续阅读
更早的文章

二维码相关需求实现

参考资料zxing扫描二维码和识别图片二维码及其优化策略BGAQRCode-Android智能设备上的二维码解码优化…

继续阅读