美文网首页
解读 hello-kotlin 项目

解读 hello-kotlin 项目

作者: codergege | 来源:发表于2018-11-14 12:56 被阅读0次

    回到目录
    项目源码 hello-kotlin 项目


    上一节我们用 gradle + spring boot 搭建好了学习 kotlin 的开发环境, 这一节我们解读
    一下这些代码是怎么回事(gradle 和 spring boot 的知识不在本文讨论范围).

    Kotlin 源文件

    Kotlin 源码文件都以 kt 作为后缀, 文件名是可以任意的. 最终编译后, 会生成"文件名Kt"
    的 class 文件. 例如 HelloKotlinApplication.kt 文件会被编译成 HelloKotlinApplicationKt.class

    Kotlin 的 main() 方法

    项目中的 HelloKotlinApplication.kt 文件里存放了 main() 方法:

    fun main(args: Array<String>) { 
        // 忽略下面这句, 这个是启动 springboot 的
        runApplication<HelloKotlinApplication>(*args)
        // 这里才是我们写的打印语句
        println("Hello, Kotlin!")
    }
    

    看源代码, 我们惊奇的发型 main() 方法并没有放在类里面, 这个在 kotlin 中称为"包级方法"或"顶级方法".
    实际上, 底层实现时, mian() 是放在 HelloKotlinApplicationKt 类里的一个静态方法.
    就跟 java 中的 main() 入口方法一样.

    // 反编译字节码为 java 代码后的样子
    public final class HelloKotlinApplicationKt {
       public static final void main(@NotNull String[] args) {
          Intrinsics.checkParameterIsNotNull(args, "args");
          String var1 = "Hello, Kotlin!";
          System.out.println(var1);
       }
    }
    

    方法

    Kotlin 中定义一个方法是用 fun 关键字的, 完整语法是 可见修饰符 fun 函数名(参数列表): 返回值 { 函数体 }

    如果没有返回值, 可以省略不写;

    参数的语法是 变量: 类型

    省略可见修饰符的话, 默认是 public 的.

    println()

    我们继续看 println("Hello, Kotlin!") 这一句, 它没有分号! 没有看到调用者!

    Kotlin 中不用写分号, 这个太棒了, 记住这点就可以(一开始习惯改不了没关系, IDE 会
    提醒你的.)

    我们重点需要关注的点是, println() 这个方法怎么就凭空冒出来了呢? 我们 ctrl + 左键
    追踪一下源码看看:

    @file:JvmName("ConsoleKt")
    
    package kotlin.io
    
    // ...
    @kotlin.internal.InlineOnly
    public actual inline fun println(message: Any?) {
        System.out.println(message)
    }
    // ... 
    

    首先 @file:JvmName("ConsoleKt") 是告诉编译器, 将这个文件编译为 ConsoleKt.class.

    这是一个 inline 方法, println(message: Any?) 方法将不会生成函数对象, 而是编译后
    直接将 System.out.println(message) 这句代码替换到调用 println() 函数的地方.

    我们再看下 HelloKotlinApplication.kt 反编译后的 java 代码:

    // 内联函数调用的地方, 编译器为我们生成的代码
    String var3 = "Hello, Kotlin!";
    System.out.println(var3);
    

    自动导包

    上面解释了没有调用对象的问题, 但还有一个问题没有解释清楚, 那就是没有 import 语句
    怎么就能直接用 println() 函数了呢. 我们第一反应肯定是编译器帮我们默认导包了, 就像
    groovy 中的行为一样.

    没错, 去官方文档上查找一番, 我们发现 kotlin 已经默认帮我们导入了很多包了:

    • kotlin.*
    • kotlin.annotation.*
    • kotlin.collections.*
    • kotlin.comparisons.* (since 1.1)
    • kotlin.io.*
    • kotlin.ranges.*
    • kotlin.sequences.*
    • kotlin.text.*

    可以看到, println() 方法所在的 io 包已经被导入了.

    包级方法并不需要用 类名.方法名的方式调用

    Kotlin 中, 一个包级方法只要导入包后, 不需要再像 java 调用静态方法那样前面加个类名.
    在底层, 编译器会帮我们做这项工作.

    做个实验, 在 test 下,
    新建 cn.codergege.demo.io 下 MyConsole.kt 文件, 定义了一个包级方法 myprintln():

    @file:JvmName("MyConsoleKt")
    
    package cn.codergege.demo.io
    
    fun myprintln(message: Any?) {
        System.out.println(message)
    }
    

    然后新建 testio 下 MyConsoleTest 文件, 使用 myprintln() 方法:

    // 导入我们 io 包下的所有类
    import cn.codergege.demo.io.*
    import org.junit.jupiter.api.Test
    import org.springframework.boot.test.context.SpringBootTest
    
    @SpringBootTest
    class MyConsoleTest {
        @Test
        fun testMyprintln() {
            // 导入包后, 包级方法就可以直接用了.
            myprintln("aa")
        }
    }
    

    总结

    这一节我们研究了 kotlin 源文件编译成 class 文件后文件名会改变; main() 是一种包级
    方法; println() 方法是如何被调用的;


    回到目录

    相关文章

      网友评论

          本文标题:解读 hello-kotlin 项目

          本文链接:https://www.haomeiwen.com/subject/zhadfqtx.html