速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

Kotlin (1) -- 基础篇

  • 2019-09-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-09-20 12:011091

评论

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

分布式团队的高效站立会说明书 | Liga译文

LigaAI

高效工作 敏捷开发 开发团队 每日站会 企业号九月金秋榜

音视频开发进阶|第六讲:色彩和色彩空间·上篇

ZEGO即构

音视频开发 色彩 色彩空间

大数据培训前景怎么样

小谷哥

LeetCode-58. 最后一个单词的长度(java)

bug菌

Leet Code 每日一题 9月月更

DevOps 团队如何防御 API 攻击

SEAL安全

DevOps DevSecOps 软件供应链安全

软件测试 | 测试开发 | 构建测试平台与对应的组织架构需要哪些能力?

测吧(北京)科技有限公司

测试

设计模式的艺术 第十七章命令设计模式练习(开发一个基于Windows平台的公告板系统。该系统提供了一个主菜单(Menu),主菜单包含一些菜单项,Menu类可以增加菜单项。菜单项主要方法是click(),每个菜单项包含一个抽象命令类)

代廉洁

设计模式的艺术

计算机网络体概念

StackOverflow

编程 计算机网络 9月月更

首次公开到知乎爆火!基于SpringCloud+SpringBoot+Vue电子版项目实战教程,附完整源码

退休的汤姆

Java spring 程序员 面试题 阿里

千锋锋友学盟分享会:程序员百万年薪进阶指

千锋IT教育

LeetCode-66. 加一(java)

bug菌

Leet Code 每日一题 9月月更

软件测试 | 测试开发 | 持续交付-Blue Ocean 应用

测吧(北京)科技有限公司

二本4年Java经验,五面阿里(定薪45K)

退休的汤姆

Java 程序员 阿里 面经 秋招

解锁云原生新场景 | 云原生加速云边端一体化发展

York

容器 云原生 边缘计算 边云协同 边缘云原生

利用GCC插件实现代码分析和安全审计

科技怪咖

阿里灵杰融合智能算力,全栈AI服务为探索者铺路

阿里云大数据AI技术

人工智能 大数据 企业号九月金秋榜

软件测试 | 测试开发 | 测试开发基础 mvn test | 利用 Maven Surefire Plugin 做测试用例基础执行管理

测吧(北京)科技有限公司

maven

51单片机定时器原理及相关器件

孤衫

C语言 单片机 9月月更

技术分享| 基于RTM 实现的呼叫邀请如何添加推送功能?

anyRTC开发者

音视频 IM 实时消息 呼叫邀请 推送

在线数据迁移,数字化时代的必修课 —— 京东云数据迁移实践

京东科技开发者

数据 数据迁移 上云 redis'

游戏技术加速数实融合,网易伏羲挖掘机器人首次曝光

网易伏羲

人工智能 机器学习 工程实践

学员参加前端培训哪里比较靠谱?

小谷哥

零基础学习java培训是否适合参加

小谷哥

Apache DolphinScheduler PMC:开源不一定也要九死一生

白鲸开源

海豚调度 开源社区 Apache DolphinScheduler 开源文化 #开源

零基础如何参加大数据培训

小谷哥

Substrate技术及生态8月大事记 | 波卡发布新版本,XCM协议更新

One Block Community

区块链 技术 开发者 Substrate 更新

从零教你使用MindStudio进行Pytorch离线推理全流程

华为云开发者联盟

Python 人工智能 企业号九月金秋榜

在java培训中心怎样才能快速学习?

小谷哥

从云计算到函数计算

Serverless Devs

云计算 阿里云 AWS

Dubbo 3 StateRouter:下一代微服务高效流量路由

阿里巴巴中间件

阿里云 开源 微服务 dubbo 中间件

基于阿里云Serverless函数计算开发的疫情数据统计推送机器人

Serverless Devs

Kotlin (1) --基础篇_文化 & 方法_赵瑞超_InfoQ精选文章