写点什么

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

评论

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

python入门之数据库操作

技能实验室

Python 10月月更

python将视频抽帧的的多种方式

技能实验室

10月月更

python入门之内置模块argparse

技能实验室

Python 10月月更

使用python生成文字图片,画圆圈 ,生成圆形图片

技能实验室

10月月更

Java读取csv文件的三种方式

技能实验室

10月月更

python实现ftp服务端和客户端

技能实验室

Python 10月月更

python入门之发送邮件

技能实验室

Python 10月月更

python入门之时间处理日期库

技能实验室

Python 10月月更

python版局域网端口扫描

技能实验室

Python 10月月更

Springboot项目启动后获取配置属性

技能实验室

10月月更

国家级认证!青藤获得安全运营类一级资质

青藤云安全

网络安全 主机安全 青藤云安全

翻译API的python调用方式

技能实验室

Python 10月月更

使用python给图片加个盲水印

技能实验室

Python 10月月更

在Centos6.10安装python3后安装第三方包遇到的问题

技能实验室

Python 10月月更

电网攻击频发,云原生架构正在成为众矢之的

青藤云安全

网络安全 主机安全 青藤云安全

LED显示屏由什么组成?

Dylan

LED显示屏 全彩LED显示屏 led显示屏厂家

使用python时刻中监控文件夹,记录文件夹中文件异常信息

技能实验室

Python 10月月更

python中的一个实用的库imghdr,用于探测图片格式

技能实验室

Python 10月月更

【融云出海白皮书免费看】出海洞察之印尼的「新兴市场启示录」

融云 RongCloud

白皮书 出海

使用python处理视频的库moviepy

技能实验室

python 3.5+ 10月月更

深入RocketMQ-消息原理篇

C++后台开发

RocketMQ 消息队列 后端开发 linux开发 C++开发

使用python监控linux服务器

技能实验室

10月月更

使用python实现一个文件搜索功能,类似于Everything功能

技能实验室

Python 10月月更

3DCAT教育合作伙伴招募 | 价值80w权益等你来,立享最高级别技术支持

3DCAT实时渲染

云计算 元宇宙 实时渲染 实时云渲染 云VR

使用python校验密码强度

技能实验室

python 3.5+ 10月月更

windows机器配置自签名ssl证书,部署文件服务器

技能实验室

windows SSL证书 10月月更

python入门之os模块和platform模块

技能实验室

10月月更

使用Idea搭建App开发环境,创建安卓工程

技能实验室

android IDEA 10月月更

python替换图片背景色,适用于制作证件照

技能实验室

python 3.5+ 10月月更

使用python提供一个简单的restful接口

技能实验室

python 3.5+ 10月月更

记一次应用接入第三方统一认证服务的过程,基于JWT和OAuth2.0

技能实验室

Java 10月月更

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