一、准备工作
Kotlin 是 JetBrains 在 2010 年推出的基于 JVM 的新编程语言。开发者称,设计它的目的是避免 Java 语言编程中的一些难题。比如:在 Kotlin 中类型系统控制了空指针引用,可以有效避免 Java 中常见的NullPointException。
相比于 Java,Kotlin 有着更好的语法结构,安全性和开发工具支持。
Kotlin 中没有基础类型,数组是定长的,泛型是安全的,即便运行时也是安全的。此外,该语言支持闭包,还可通过内联进行优化。不过,它不支持检查异常(Checked Exceptions),许多语言设计者认为这是它的瑕疵。不论如何,重要的是 Java 和 Kotlin 之间的互操作性:Kotlin 可以调用 Java,反之亦可。
Android Studio支持Kotlin环境,Android开发者可以直接使用
如果是自己练习一些语法什么的,强烈建议使用Intellij IDEA
安装 Intellij IDEA
官网下载,可以使用社区版。 https://www.jetbrains.com/idea/download/
新建工程
打开 IDEA -> New Project -> Lanuge 选Kotlin 即可
下载依赖需要等一会
在工程中新建 kt 文件练习
入口即是一个 main 函数,如下
文件以kt结尾,变量声明,var,val,空安全,函数声明,模板语法($)
// Utils.kt fun echo(name: String) { println("$name") } // Main.java public static void main(String[] args) { UtilsKt.echo("hello"); }
object Test { fun sayMessage(msg: String) { println(msg) } } kotlin code Test.sayMessage("hello") java code Test.INSTANCE.sayMessage("hello");
java code TestMain.class kotlin code TestMain::class.java 例如: private val log: LogHelper = LogHelper(AiVisualService::class.java.simpleName)
java code public class JavaMain { public static String in = "in"; } kotlin code fun main(args: Array
没有封装类,只有基础类型,比如没有 Integer, 跟java不一样
java code String format(String str) { return str.isEmpty() ? null : str; } kotlin code fun function(str: String) { val fmt1 = format(str) // 自动推断类型,String!, 临时的兼容类型 println(fmt1.length) // 运行时报空指针 val fmt2:String = format(str) // 会不会有问题? val fmt3:String? = format(str) println(fmt3?.length) // 空安全,不会有问题 } fun main(args: Array
object Test { val TAG:String = "test" fun sayMessage(msg: String) { println(msg) } } kotlin code Test.sayMessage("hello") java code Test.INSTANCE.sayMessage("hello"); 思考:java如何不加添加 INSTANCE? 答案:@JvmStatic 关键字 object Test { @JvmStatic fun sayMessage(msg: String) { println(msg) } } kotlin code Test.sayMessage("hello") java code Test.sayMessage("hello");
函数是一等公民,而不是跟Java一样只有方法
fun echo(name: String) { println("$name") } fun echo(name: String = "ZhangTao") { println("$name") } fun echo(name: String) = println("$name") // 只有一个语句时,可这样简写
一般情况下不推荐使用,可以在特殊场景使用,如下
用途:在某些条件下触发递归的函数,或不希望被外部函数访问到的函数
fun function() { val str = "hello world" fun say(count: Int = 10) { println(str) if (count > 0) { say(count - 1) } } say() }
kotlin code val file = File() val content = file.readText() java code String content = FilesKt.readText(file, Charsets.UTF_8);
主要用途:对第三方SDK,或不能控制的类,需要扩展时,可以使用扩展函数。
注意:静态的给一个类添加成员变量或成员方法,不具备动态特性。
fun main(args: Array
Lambda闭包声明
val echo = { name: String -> println(name) } fun main(args: Array
Lambda 最多只有22个参数,如何突破限制?
fun onlyif(isDebug: Boolean, block:() -> Unit) { if (isDebug) block() } fun main(args: Array
val runnable = Runnable { println("Runnable::run") } val function: () -> Unit function = runnable::run 使用(接前一段代码): onlyif(true, function)
Kotlin 的 Lambda 是一个匿名对象
可以使用 inline 修饰方法,这样当方法在编译 时就会拆解方法的调用为语句调用,进而减少 创建不必要的对象
最后:inline不要滥用,最好只用于修饰高阶函数
class MainActivity : AppCompatActivity() class MainActivity : AppCompatActivity(), OnClickListener Kotlin 的类默认是 public final 的 open class MainActivity : AppCompatActivity() open class MainActivity : AppCompatActivity(), OnClickListener
主构造函数: 规范来说,都是以_xxx的形式命名的,临时的输入类型,不能直接用,需要通过声明接收下来,成为变量才
class Test03(_name:String,_sex:Char,_age:Int,_info:String) //主构造函数 { var sex=_sex get() = field var age=_age+10 get() = field var info=_info get() = field var name=_name get() = field //get函数不允许私有化 private set(value) {field=value} fun show(){ println(name) // name==this.getName() println(sex) println(info) println(age) } } fun main() { val test03 = Test03("李渐渐", '女', 10, "信息") //test03.name="李防范" set被私有化了,不能调用 test03.show() }
使用次构造函数时,先调用主构造函数,然后执行{}内的内容
class TestView : View { constructor(context: Context) : super(context) { println("constructor") } constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) }
// name/age/sex 临时变量可以在构造函数代码块中使用 但不能在方法中使用,要想使用,必须先进行二次接收
class Test07(name:String,age:Int,sex:Char){ // init 主构造函数的代码块 init { println("主构造函数被调用了: $age") //require 验证是否符合规范 不符合的抛出异常并输出 require(age>0){ "年龄输入不对" } } constructor(name:String):this("王五",55,'男'){ println("次构造函数被调用了: $name") } } fun main() { Test07("李四",88,'女') Test07("二狗") }
private protected public internal : Kotlin 特有的。 模块中能访问,跨模块就不能访问了。 例如 Android中的 library/app modual
class StringUtils { companion object { fun isEmpty(str: String): Boolean { return "" == str } } } StringUtils.isEmpty("sdfd") java code: StringUtils.Companion.isEmpty("");
可使用伴生对象声明单例,是比较推荐的单例写法
class Single private constructor() { companion object { fun get(): Single { return Holder.instance } } private object Holder { val instance = Single() } }
Kotlin使用动态代理不用像java那么麻烦,kotlin语言原生就支持动态代理,只需要通过by关键字即可
interface Animal { fun bark() } class Dog : Animal { override fun bark() { println("Wang") } } class Zoo(animal: Animal) : Animal by animal fun main(args: Array
Kotlin中的动态代理编译后会转成静态代理,比Java的动态代理(反射实现)效率高。
data class User(var id: Int, var name: String) public final getter()/setter() toString() hashCode() equals() copy()
enum class Command { A, B, C, D } fun exec(command: Command) = when (command) { Command.A -> { } Command.B -> { } Command.C -> { } Command.D -> { } }
Kotlin中一般不使用枚举类,而是使用更加强大的枚举类 --- 密闭类
sealed class SuperCommand { object A : SuperCommand() object B : SuperCommand() object C : SuperCommand() object D : SuperCommand() class E : SuperCommand() // 密闭类可以有子类,但必须与密闭类写在一个同文件中 } fun exec(superCommand: SuperCommand) = when (superCommand) { SuperCommand.A -> { } //... is SuperCommand.E -> { } }