PCon全球产品创新大会最新日程一览,这里直达 了解详情
写点什么

Kotlin (1) -- 基础篇

  • 2019 年 9 月 20 日
  • 本文字数:7493 字

    阅读完需:约 25 分钟

Kotlin (1) --基础篇

本文旨在通过介绍 Kotlin 的基础知识、开发环境配置、基本语法,使工程师对 Kotlin 形成整体认识,顺利上手 Kotlin 开发;对比 Kotlin 和 Java 的不同用法,Kotlin 和 Java 混合编译相互调用的方法,为工程师开始 Java 代码改造、进行现有 Java 工程下的混合开发做好准备。


Kotlin 简介

  • 基于 JVM 运行的静态类型编程语言:

  • 提供编译器(compiler),库(libraries),工具(tooling)

  • JetBrains 推出,旨在:

  • 创建一种兼容 Java 的语言;


编译速度和执行效率至少同 Java 一样,原因包括:


  • Kotlin Lib 很小,引入开销很小;

  • 使用 lambda,免去创建很多新对象;

  • 方法 inline 设置操作,减少运行时进栈、出栈、保存状态的开销。

  • 比 Java 更安全;

  • 比 Java 更简洁;

  • 比最成熟的竞争者 Scala 还简单。


Kotlin 特性:


  • 实用(Pragmatic);

  • 简洁(Concise);

  • 安全(Safe)。


版本演进


  • 2010 年:Kotlin 进入开发;

  • 2011 年 7 月:推出 Kotlin;

  • 2016.2.15:官方发布第一个 release 版本 v1.0;

  • 2017.3.2:Kotlin v1.1 release 版本;

  • 2017.5.19:Google 正式宣布官方支持 Kotlin,将 Kotlin 作为 Android 开发一级编程语言(First-Class Language)。


目标人群:



  • 基于 JVM,可用于服务端开发;

  • 基于 Android(JVM)和 Browser(JavaScript),可用于客户端开发,前端开发;

  • 基于 Native,可绕过 JVM 与底层代码打交道。


Kotlin 开发环境配置及代码运行

  • 基于 JVM 运行的静态类型编程语言:


环境配置


IDE


o IntelliJ IDEA


§ IDE 15 及以上已经集成支持 Kotlin;


§ 15 以下安装 Kotlin 插件:Preferences–>Pugins–>搜索 Kotlin


o Android Studio


§ 添加 Kotlin 语言库和序列化对象 Parcelable 插件:


§ AS 3.0 及以上已经集成;


§ AS 3.0 前,Settings—>Plugins—>InstallJetBrains plugin—>Kotlin


§ 在项目中配置的三个方式:


  1. Tools|Kotlin|ConfigureKotlin

  2. 打开一个 Java file,通过以下三种方式让 Java 转 Kotlin(不可以从 Kotlin 转 Java),首次操作并会提示配置:

  3. Code—>Convert Javafile to Kotlin file(ALT⇧⌘K)

  4. Help—>Find Action(⇧⌘A):输入 Convert Java file to Kotlin file

  5. .java 中的代码片段拷贝到 .kt 后即自动转换。

  6. 新建 Kotlin flie 提示配置。


§ 配置生效后的效果:


在 build.gradle(Project)中会自动添加如下:


buildscript{
ext.kotlin_version = '1.1.2-5'
dependencies {
classpath"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
复制代码


在 build.gradle(Module)中添加如下:


applyplugin: 'kotlin-android'
dependencies{
compile"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}
复制代码


Eclipse


o 安装插件:Help–> EclipseMarketplace…–> 搜索 Kotlin


· Online playground


o https://try.kotl.in/


o 无需安装、配置,可编写、编译、运行。


· 支持 Maven/Ant/Gradle


· 支持 cmd line:


// Compile
kotlinc<source file or directory> -include-runtime -d <jar name>
// Executecode
java -jar<jar name>
复制代码


代码运行


· IntelliJ


o New Project :选择 Kotlin(JVM)


o 在 src 下 New Kotlin File/Class:MyTest


o 点击左侧图标运行



并会自动完成下图配置。


特别注意:config 是 MyTestKt,而不是 MyTest,自行 Edit Config 时,在 Main Class 栏位不要填错。



Kotlin 语法

本节列出 Kotlin 的基本语法,尤其是和 Java 写法不同之处。


1.变量(Variables)


用关键字"val" 声明常量,对应 java 中的"final";用关键字"var" 声明变量,对应 Java 中的非"final"。Kotlin 支持类型推断,省略变量类型。


valanswer: Int = 42
/ / 类型推断,可以省略类型:
val answer= 42
复制代码


2.函数(Functions)


Kotlin 对于函数定义和 Java 区别较大, Kotlin 中一个函数的构成如下图:



有块函数体(blockbody function)和表达式函数体(expression body function)两种形式。


// blockbody function
fun max(a:Int, b: Int): Int
{
return if (a > b) a else b
}
//expression body function
fun max(a:Int, b: Int): Int = if (a > b) a else b
复制代码


包级别函数(top-levelfunction / Package-level function)


不属于任何类,属于当前包(package),其功能类似于 Java 中提供静态方法的工具类。


// Java 中的静态工具类:
packagestrings;
publicclass JoinKt {
public static String joinToString(...) {... }
}
复制代码


// Kotlin 中使用包级别函数:
packagestrings
funjoinToString(...): String { ...
Kotlin 的包级别函数在 Java 中的调用方式:
// 在 Kotlin 中 package 前加入注释
@file:JvmName("StringFunctions")
packagestrings
funjoinToString(...): String { ... }
复制代码


// 在 Java 中调用:
importstrings.StringFunctions;
StringFunctions.joinToString(list,", ", "", "");
复制代码


扩展函数(extension function)


在类外定义,但是是被扩展类的类成员。其格式如下:



其中 receiver type 是被新增的函数所在的类。receiver object 是调用此方法的对象。


Java 没有的特性。


举例:在 StringUtil.kt 文件中,扩展 String 类的一个方法,名为 lastChar(),用于返回字符串的最后一个字符。


packagestrings


funString.lastChar(): Char = get(length - 1)


lastChar() 这个方法在 Kotlin 和 Java 中都可以被使用:


// Kotlin 中调用:


println(“Kotlin”.lastChar())


// Java 中调用:


char c =StringUtilKt.lastChar(“Kotlin”);


在 Android 中,为 Framework 类定义扩展函数,可以简化系统方法的调用方式。


举例:为 Activity 扩展 toast 方法,在派生 Activity 中直接调用 toast() 取代 Toast.makeTest().show()。


//Kotlin


fun Activity.toast(message:CharSequence, duration: Int = Toast.LENGTH_SHORT) {


Toast.makeText(this, message,duration).show()
复制代码


}


高阶函数


可以接受函数作为参数,也可以返回函数作为结果。Java 没有的特性。举例:Android 中使用 SharePreference 来存储数据,需要包括 edit()、appply()等方法。可以使用 Kotlin 封装成一个传入函数参数的方法,直接调用。如下:


//kotlin
funSharedPreferences.editor(f: (SharedPreferences.Editor) -> Unit) {
val editor = edit()
f(editor)
editor.apply()
}
//实际调用
PreferenceManager.getDefaultSharedPreferences(this).editor{
it.putBoolean("installed", true)
}
复制代码


1.#### 控制结构(Control)


when


比 Java 中的 switch 强大,条件支持类型更宽松。


// 一对一,其中 Color 是封装类,不是简单类型。
fungetMnemonic(color: Color) =
when(color) {
RED -> "Richard"
ORANGE -> "Of"
YELLOW -> "York"
GREEN -> "Gave"
BLUE -> "Battle"
INDIGO -> "In"
VIOLET -> "Vain"
}


// 多对一
fungetWarmth(color: Color) = when(color)
{
RED, ORANGE, YELLOW -> "warm"
GREEN -> "neutral"
BLUE, INDIGO, VIOLET -> "cold"
}

// 混合
funmix(c1: Color, c2: Color) = when (setOf(c1, c2)) {
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO
else -> throw Exception("Dirtycolor")
}
复制代码


循环


while 和 Java 写法相同。for 写法如下:


for(x inrange)
复制代码


range 是范围,可以有以下几种写法:


1…10 // 表示 [1,10]


1 until 10// 表示 [1, 10)


100 downTo1 step 2 //表示 100, 98,96…2


1. #### 集合(collection)


提供新 API,比 Java 的定义方式简单。


val set =setOf(1, 7, 53)


val list =listOf(1, 7, 53)


val map =mapOf(1 to “one”, 7 to “seven”, 53 to"fifty-three")


1. #### Interface


与 Java 相比, Kotlin 一个显著的改进之处是:接口支持提供缺省实现的方法,派生类不再用实现所有接口方法。同时 Kotlin 中,复写方法必须显示声明 override,否则不被编译。


interfaceClickable {
fun click()
// 可以有缺省实现的接口函数
fun showOff() = println("I'mclickable!")
}

interfaceFocusable {
fun showOff() = println("I'mfocusable!")
}

//override 必须写上
classButton : Clickable, Focusable {
override fun click() = println("I wasclicked")
// Clickable, Focusable 都有 showOff(),所以此处必须复写 showOff(),否则编译错误。反之有缺省实现的函数可以不复写。
override fun showOff() {
// java 的写法是:Clickable.super.showOff()
super<Clickable>.showOff()
super<Focusable>.showOff()
}
}
复制代码


1. #### 类


Java 中类和方法默认是可继承的( open),Kotlin 中默认是不可继承的( final )。这是因为:基类的修改易造成派生类的写法不符合之前的预期,破坏了稳定性。


// Button 可以被继承
open classButton : Clickable {
// final
fun disable() {}
// open
open fun animate() {}
//继承自接口,也继承了其open属性。
override fun click() {}
//显示声明为final,将改变其open属性。
final override fun click() {}
}
复制代码


抽象类


Kotlin 中,抽象函数必须被派生类实现,默认为 open,非抽象函数默认为 final,需要被继承要标记 open。


//抽象类
abstractclass Animated {
abstract fun animate()
open fun stopAnimating() { }
fun animateTwice() { }
}
复制代码


类的构造函数


Kotlin 与 Java 构造函数区别较大。 Kotlin 包括主构造函数和次构造函数。


(1) 主构造函数(primary constructor)在类名后直接用 () 或 constructor() 定义参数,个数为一个或没有。在构造函数中为属性设置默认值,解决了 Java 多构造函数。


// 在构造函数中声明的参数,它们默认属于类的公有字段,可以直接被其他类访问到,如果不想被访问到,要用 private 修饰。
// valnickname
classUser(val nickname: String)
classUser(private val nickname: String)
classSecretive private constructor() {}
// 有默认值的构造函数。解决 Java 的多构造函数。
classUser(val nickname: String,
valisSubscribed: Boolean = true)
// 使用方式:
val user1= User("alice")
val user2= User("aclice", flase)
复制代码


(2) 次构造函数(Secondary constructor):在{}中定义,个数为没有、一个或多个。可用于和 Java 互调。


classMyButton : View {
//this继承自自己类的构造函数
constructor(ctx: Context): this(ctx,MY_STYLE) {
}
//super使用父类的构造函数
constructor(ctx: Context, attr:AttributeSet): super(ctx, attr) {
}
}
复制代码


Data Class


Kotlin 特有,不用 IDE 生成模板代码,而是编译成 class 过程中插入 toString()(实例所有变量的 String 表示)、equals()(实例所有变量的值比较)、hasCode()(实例的 HashCode)等方法。无需显式 override


data classUser(val nickname: String,
val isSubscribed: Boolean = true)
val user1= User("Bob", false)
val user2= User("Bob", false)
println(user1)
println(user1.equals(user2))

// 结果为:
User(nickname=Bob,isSubscribed=false)
true

// 如果是普通class,且没有重写toString() 等方法,结果为:
User@78308db1
false
复制代码


可以将 dataClass 的.kt 编译成.class,再反编译成.java,看它被自动插入了的方法。


1. #### object 关键字


Kotlin 特有,在定义类、属性、方法、块的同时创建出一个实例 INSTANCE,而无需调用构造函数,所以不用为 object 类定义构造函数。


object Payroll{
val allEmployees =arrayListOf<Person>()
fun calculateSalary() {
for (person in allEmployees) {
...
}
}
}
// 直接用类名调用
Payroll.allEmployees.add(Person(...))
Payroll.calculateSalary()
复制代码


可用于 Java 中静态方法改造为 Kotlin 方法后,用 Java 调用 Kotlin 中方法:


// Kotlin 改造的静态方法
objectStringUtils {
@JvmStatic fun isEmpty(str: String):Boolean {
return "" == str
}

fun isEmpty2(str: String): Boolean {
return "" == str
}
}

// 在 Java 中两种调用方法:
// 为了让 Java 调用,使用@JvmStatic
StringUtils.isEmpty("hello");
// objectclass,获取实例再调用。
StringUtils.INSTANCE.isEmpty2("hello");
复制代码


介绍语法过程中,涉及到了 Kotlin 文件结构,这里总结一下:


· package


o package 用于在命名空间组织代码,而非用于可见性;


o package 内多个文件间的方法可以直接调用到;


o package 间用 import。


· class, function, property


o 一个 .kt file 可以包含多个 class;


o 包级别函数(top-level function)和包级别属性(top-level property)不属于任何类。


Kotlin 与 Java 相比的特性

本节列出 Kotlin 的基本语法,尤其是和 Java 写法不同之处。


前文讲到一些 Kotlin 较 Java 相比的特性,包括支持类型推断简化变量定义方式,支持扩展函数方便方法调用,支持缺省参数简化多构造函数或多复写,支持缺省函数使接口继承不用重写所有方法等,再介绍几个:


空指针检测 NullPointerException


通过编译报错,预防潜在空指针;通过安全访问方式代替之前的 != null 的繁琐使用方式。


var s1:String? = "abc"
if(s1!!.length == 1)
if(s1?.length == 1)
复制代码


类型转换异常检测 ClassCastException


关键字 is 用于类型检测及转换。类型不匹配不执行 if 语句;类型匹配直接使用,无需显式强转。


if (s1 isString) {
println(s1.toUpperCase())
}
复制代码


lateinit


通常,类的成员变量声明时必须初始化,否则编译错误。使用 lateinit 可以将初始化延迟到使用时。


  private lateinit var textview: TextView
复制代码


Kotlin 与 Java 混合编程

除了前面章节示例中的互相调用,这里再列举一些互相调用的例子。


1. Kotlin 调用 Java


如果 Java 类存在 setXXX 和 getXXX 的方法,Kotlin 即可以直接调用其属性。


//Java
publicclass DataClass {
private int id;

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}}
// Kotlin
funmain(args: Array<String>) {
val dataClass = DataClass()
dataClass.id = 0
println(dataClass.id)
}
复制代码


Java 方法名用的是 Kotlin 关键字时,需要反引号``包起来从能被 Kotlin 调用。


foo.`is`(bar)
复制代码


Kotlin 在访问 Java 变量或 Java 方法时,变量、方法的参数和返回值(称为:平台类型 Platform Type)的空与否由我们自己决定,编译不会报错。所以在 Java 类中可以用 @NotNull、@Nullable 做好提示。


//Java
publicclass DataClass {
private String id;

public String getId() {
return null;
}
}
//Kotlin
funmain(args: Array<String>) {
val nullSafetyJava = DataClass()
val data = nullSafetyJava.id
//编译不报错,但是运行时dataCannotBeNull这行报错。
val dataCanBeNull: String? = data
val dataCannotBeNull: String = data
}
//
// Java
publicabstract class NullSafetyAbsClass {
public abstract @NotNull StringformatDate(Date date);}
//开发者在Kotlin中使用时,根据@NotNull注释就需要做好保护。
classNullSafetySubClass : NullSafetyAbsClass(){
override fun formatDate(date: Date?):String? {
return date?.toString()
}
}

funmain(args: Array<String>) {
val nullSafetySubClass =NullSafetySubClass()
val formattedDate: String? =nullSafetySubClass.formatDate(Date())
println(formattedDate)
}
复制代码


2. Java 调用 Kotlin


Kotlin 自动生成属性对应的 set、get 方法(val:生成 getxxx(),var: 生成 getxxx()和 setxxx()),isxxx 属性生成 isxxx()和 setxxx(),不仅适用于 boolean,同样适用于任何类型。


class User(val nickname: String, val isOpen: Boolean)
//Java中调用
User user = new User("abc",true);

public void getProperty() {
user.getNickname();
user.isOpen();
}
复制代码


Java 调用 Kotlin 有默认值参数的函数,需传入完整的实参列表。但是如果 Kotlin 对函数增加 @JvmOverloads 注释,编译后的 class 会自动加入其它参数个数的构造函数, Java 就可以根据所需使用相应参数的构造函数。


//Kotlin
classOverloads {

fun overloaded(a: Int, b: Int = 0, c: Int =1){
}
}
//Java 中使用:
newOverloads().overloaded(0, 0, 1);

//Kotlin进行改写,加入 @JvmOverloads
classOverloads{

@JvmOverloads
fun overloaded(a: Int, b: Int = 0, c: Int =1) {
}

}
复制代码


Kotlin 与 Java 混合编程

介绍一个好用的第三方库。


Anko


辅助 Android 开发的第三方库,使开发者可以忽略 Java 版本对 Android SDK 的限制。其主要模块和功能包括:


· Anko Commons:封装 Intents、Dialog 和 toasts、Logging、Resources and dimensions 的方法;


· Anko Layouts:支持 DSL(domainspecific languages),让 Android 布局写法更简单、相同逻辑可复用、避免了 xml 渲染为对象的消耗;


· Anko SQLite:用链式调用支持数据库访问;


· Anko Coroutines:基于 kotlinx.coroutines 库。


Anko 源码及使用方法可参考:https://github.com/Kotlin/anko


配置方法:


dependencies{
compile"org.jetbrains.anko:anko:$anko_version"
}
//按需引入
dependencies{
// Anko Commons
compile"org.jetbrains.anko:anko-commons:$anko_version"

// Anko Layouts
compile"org.jetbrains.anko:anko-sdk25:$anko_version" // sdk15, sdk19, sdk21,sdk23 are also available
compile"org.jetbrains.anko:anko-appcompat-v7:$anko_version"

// Coroutine listeners for Anko Layouts
compile "org.jetbrains.anko:anko-sdk25-coroutines:$anko_version"
compile"org.jetbrains.anko:anko-appcompat-v7-coroutines:$anko_version"

// Anko SQLite
compile"org.jetbrains.anko:anko-sqlite:$anko_version"
}
}
复制代码


Anko Layouts 举个例子:


verticalLayout{
val email= editText
{ hint ="Email" }
valpassword = editText { hint = "Password"

transformationMethod =PasswordTransformationMethod.getInstance()
}
button("LogIn")
{ onClick {
logIn(email.text,password.text) }
} }
复制代码


用 DSL 定义布局,抽取公共逻辑,笔者认为可以用于布局模板化开发。


Kotlin 更多特性及实践,后继继续分享给大家。


本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。


原文链接:


https://mp.weixin.qq.com/s/T5Q7lH50RuR6ISCjFotpDg


2019 年 9 月 20 日 12:01451

评论

发布
暂无评论
发现更多内容

Flutter开发桌面应用-第一个windwos桌面应用,androidframework视频

android 程序员 移动开发

Fragment新功能,setMaxLifecycle了解一下,一文详解

android 程序员 移动开发

Flutter动手实战,大佬手把手教你如何仿写出大厂的APP,Android软件开发面试题

android 程序员 移动开发

Flutter开发之Dart的数据类型01,安卓开发面试自我介绍

android 程序员 移动开发

Flutter混合开发(三):Android与Flutter之间通信详细指南

android 程序员 移动开发

用技术变革传统康养行业,智慧养老的正确打开方式

华为云开发者社区

IoT 华为云 康养 智慧养老 智慧康养物联网加速器

GitHub标星5-3K【字节跳动大牛】手把手讲解-Android-Hook入门Demo

android 程序员 移动开发

GitHub标星9,handler机制

android 程序员 移动开发

从厂商主张到客户主见,4个变化揭示 Serverless 的不同

望宸

Serverless 容器 云原生 k8s

Flutter学习之认知基础组件,android手机开发教程

android 程序员 移动开发

Framework掌握不熟?字节跳动大牛带你系统化学习,成功定级腾讯T3-2

android 程序员 移动开发

GitHub标星8-3k的学习习惯,未来的Android高级架构师:别让这几个点毁了你

android 程序员 移动开发

Flutter之撸一个漂亮的登录界面的总结,Android性能优化之启动优化实战篇

android 程序员 移动开发

Flutter仿钉钉考勤日历,html5移动端

android 程序员 移动开发

Flutter学习之布局、交互、动画,字节跳动学习笔记

android 程序员 移动开发

GooglePlay强推的Appbundle究竟是什么?aab?不优化代码直接减少安装包大小(1)

android 程序员 移动开发

新一代云上基础技术和架构分论坛

阿里云情报局

阿里云 架构 基础设施 科技 云栖大会

Flutter图表库fl_chart的使用解析(二)-折线图,android webview

android 程序员 移动开发

Flutter基础(三)Dart快速入门,下血本买的

android 程序员 移动开发

Flutter的原理及美团的实践(中),直击优秀开源框架灵魂

android 程序员 移动开发

Flutter这么火为什么不了解一下呢?(下,2020-2021京东Android面试真题解析

android 程序员 移动开发

Fragment的使用,为什么有人说Android开发不再吃香

android 程序员 移动开发

Google 为什么以 Flutter 作为原生突破口,正式加入阿里巴巴

android 程序员 移动开发

Flutter原理:三棵重要的树(渲染过程、布局约束,android开发框架介绍

android 程序员 移动开发

Flutter提升开发效率的一些方法和工具,零基础入门学习android

android 程序员 移动开发

Fragment的通信,flutter通知推送

android 程序员 移动开发

Flutter开发中的一些Tips(二),2021年网易Android岗面试必问

android 程序员 移动开发

Glide源码难看懂?用这个角度让你事半功倍!,移动端h5页面加载慢

android 程序员 移动开发

Flutter实战之实现一个简单的新闻阅读器,html5移动端开发框架

android 程序员 移动开发

Glide加载Gif的卡顿优化思路分析,android开发项目实例记事本

android 程序员 移动开发

Flutter自适应瀑布流,深入浅出安卓开发

android 程序员 移动开发

Kotlin (1) --基础篇-InfoQ