最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

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:01863

评论

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

Web3 新手攻略:9个不可或缺的APP助力你踏入加密领域

股市老人

Web3新手入门9大必备宝藏APP

EOSdreamer111

终极对决!Bitget Wallet vs Metamask 钱包大比较!隐藏功能曝光

石头财经

华为云API图像搜索ImageSearch的快捷性—AI帮助您快速归类图片

YG科技

华为云API图像识别Image的趣味性—AI识别迈克尔·杰克逊

YG科技

Web3 新手攻略:9个不可或缺的APP助力你踏入加密领域

鳄鱼视界

区块链数字货币交易所系统软件开发详情(源码)

西安链酷科技

交易所源码 交易所搭建

WorkPlus一站式解决方案,助力企业构建统一门户系统

WorkPlus

华为云持续扎根软件工具生态,突破10倍研发效能赋能千行百业

YG科技

除了Office,这8款好用的办公软件也值得推荐!

彭宏豪95

效率 职场 软件推荐 在线白板 办公软件

Apache IoTDB 作为合作伙伴参加 Doris Summit Asia 2023!

Apache IoTDB

天谋科技与华为鲲鹏完成兼容性互认证

Apache IoTDB

Redis Scan原理

宁静知行者

redis 底层原理

AI 帮写爬虫,真的吗? CodeWhisperer:当然!

梦想橡皮擦

Web3 新手攻略:9 个不可或缺的 APP 助力你踏入加密领域

威廉META

基于 ACK Fluid 的混合云优化数据访问(三):加速第三方存储的读访问,降本增效并行

阿里巴巴云原生

阿里云 云原生 容器服务

设计师、教师、奶爸从零开始做提示词,文心一言APP让提示词“人人可用”

彭飞

请查收:赛博威TPM营销费用管理指南——费用管理类型篇

赛博威科技

营销数字化

新手必看!Bitget Wallet 和 Metamask 到底该选谁?真实对比评测

BlockChain先知

低代码开发不可能取代程序员

互联网工科生

低代码

Last Week in Milvus

Zilliz

非结构化数据 Milvus Zilliz AIGC

华为云发布CodeArts Governance开源治理服务,开源使用更安心

YG科技

国产化即时通讯平台WorkPlus,助力企业实现自主可控的沟通与协作

WorkPlus

百度世界2023剧透丨百度王颖:百度文库每周上线2-3个AI新功能,累计使用次数近亿

彭飞

别再说被八股文害惨了!GitHub阿里Java面试题库标星145K不无道理

程序员万金游

#java #面试 #编程 #程序员 #Mysql

Linux是什么,其特点是啥

二哈侠

Python 集合(Sets)1

小万哥

Python 程序员 软件 后端 开发

代码混淆界面介绍

雪奈椰子

WorkPlus私有部署即时通信助力企业信息安全与高效协作

WorkPlus

百度世界2023剧透丨肖阳:「语义检索技术+大语言模型」融合,百度「新搜索」将亮相

彭飞

最高评级!华为云CodeArts Board获信通院软件研发效能度量平台先进级认证

YG科技

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