Kotlin基础:白话文转文言文般的Kotlin常识
这是该系列的第一篇,系列文章目录如下:
- Kotlin基础:白话文转文言文般的Kotlin常识
- Kotlin基础:望文生义的Kotlin集合操作
这个系列记录的是kotlin
使用感受,其中也会穿插基础知识点,并通过项目实战代码综合运用这些知识点。
刚接触kotlin
就被它的简洁震撼到了(kotlin
的作者一定是一个极简主义!)。一起来看下kotlin
是怎么通过“断舍离”来实现简洁的:
new 分号 类型
新建对象不需要new
关键词。
任何语句的结尾不需要;
但加上也不会有语法错误。
//java
StringBuffer buffer = new StringBuffer();//kotlin
var buffer = StringBuffer()
复制代码
var
是kotlin
保留字,用于声明变量。与之对应的是val
用于声明常量。- 不需要显示指明变量类型,因为
kotlin
会根据上下文推断变量类型,这种能力称为 “类型推导” 。 - 可以通过下面的语法来指定类型:
var buffer: StringBuffer = StringBuffer()
复制代码
kotlin
中类型是后置的,在变量名后跟上: 类型
就可以显示指定类型。同理,它也用于指定函数返回值类型:
fun getMessage(): String{return "message"
}
复制代码
fun
关键字用于声明函数。
implements extends @Override
//java
public class CheckableActivity extends Activity {final public void setStatus(){}
}public class MyListener implements View.OnClickListener{@Overridepublic void onClick(View v) {}
}//kotlin
class CirclePartyListActivity : Activity() {fun setStatus(){}
}class MyListener : View.OnClickListener{override fun onClick(v: View?) {}
}
复制代码
kotlin
用:
取代了implements
和extends
保留字。@Override
也被override
保留字取代并且和函数头同行,kotlin
中的override
是必须的,而java
中是可选的。kotlin
中类和方法默认是final
的(可省略不写),这意味着默认情况下,类和方法是不允许被继承和重写的(这是为了防止脆弱的基类
,即对基类方法的修改会导致子类出现预期之外的行为)。只有通过open
保留字显示声明该类或方法可以被继承或重写:
open class A{open fun do(){}
}
复制代码
()
kotlin
的lambda
也更加简约:
//正常情况
view.setOnClickListener({ v -> v.setVisibility(View.INVISIBLE) })
//当lambda是函数的最后一个参数时,可以将其移到括号外面
view.setOnClickListener() { v -> v.setVisibility(View.INVISIBLE) }
//当函数只有一个lambda类型的参数,可以去省去括号
view.setOnClickListener { v -> v.setVisibility(View.INVISIBLE) }
//当lambda只有一个参数,可省去参数列表,在表达式部分用it引用参数
view.setOnClickListener { it.setVisibility(View.INVISIBLE) }
复制代码
getter setter
java
中,字段和其访问器的组合被称为属性,kotlin
引入了property access syntax
,它取代了字段和访问器方法,用这种方式进一步简化上面的代码:
view.setOnClickListener { it.visibility = View.INVISIBLE }
复制代码
- 所有被定义了
getter
和setter
方法的字段,在kotlin
中都可以通过赋值语法来操作。
{ } return
kotlin
中的语句和表达式的唯一区别是:表达式有值,而语句没有。如果函数体由单个表达式构成,可以省去花括号和return,并用赋值的=
表示将表达式的值赋值给返回值:
//java
public int add(int a, int b){return a+b ;
}//kotlin
fun add(a: Int, b: Int): Int = a+b
复制代码
在 lambda 表达式中包含多条语句或表达式时,若省略return
,则默认将最后一个表达式的值作为返回值:
view.setOnTouchListener { v, event ->...//do somethingfalse
}
复制代码
上述代码表示在OnTouchListener.onTouch()
中返回 false。
switch-case-break
//java
String color;
switch(colorInt){case Color.RED:color = "red";break;case Color.BLUE:color = "blue";break;default:color = "black";break;
}//kotlin
val color = when (colorInt) {Color.RED -> "red"Color.BLUE -> "blue"else -> "black"
}
复制代码
when
用于取代switch-case
,不需要在每个分支末尾调用break
,如果有一个分支命中则会立即返回。when
是一个表达式,这意味着它有返回值,返回值等于命中分支中最后一条语句的返回值。
default
java
中的default
保留字用于接口中默认方法的实现。在kotlin
中可以省去它。
//java
public interface IMessage {default String getMessage() {return "default message";}int getMessageId();
}//kotlin
interface IMessage {fun getMessage(): String {return "default message"}fun getMessageId(): Int
}
复制代码
Int
是java
中基本数据类型int
的包装类,kotlin
中没有基本数据类型。
防御式编程
//java
public class Address {private String country;public String getCountry() {return country;}
}public class Company {private Address address;public Address getAddress() {return address;}
}public class Person {private Company company;public String getCountry() {String country = null;//多次防御式编程if (company != null) {if (company.getAddress() != null) {country = company.getAddress().getCountry();}}return country;}
}//kotlin
fun Person.getCountry(): String? {return this.company?.address?.country
}
复制代码
?.
称为 安全调用运算符 ,它把判空检查和一次方法调用合并成一个操作。只有当调用变量不为null
时,才会执行调用,否则整个表达式返回null
。这意味着,不再需要防御式编程。?
置于类型之后表示这个类型可空,上面的函数声明表示此函数的返回值可能为null
。- 上面的 kotlin 代码为
Person
类添加了一个getCountry()
方法,这种技术叫扩展函数 。
扩展函数
扩展函数是一个类的成员函数,但它定义在类体外面。这样定义的好处是,可以在任何时候任何地方给类添加功能。
在扩展函数中,可以像类的其他成员函数一样访问类的属性和方法(除了被private
和protected
修饰的成员)。还可以通过this
引用类的实例,也可以省略它,把上段代码进一步简化:
fun Person.getCountry(): String? {return company?.address?.country
}
复制代码
kotlin
预定了很多扩展函数,下面就会用到其中的apply
:
冗余对象名
编程中经常会遇到“对同一个对象做多次操作”的场景,比如:
Intent intent = new Intent(this, Activity1.class);
intent.setAction("actionA");
Bundle bundle = new Bundle();
bundle.putString("content","hello");
bundle.putString("sender","taylor");
intent.putExtras(bundle);
startActivity(intent);
复制代码
其中,对象intent
和bundle
重复出现若干次,这对于极简主义的kotlin
来说不能忍,它的表达方式如下:
Intent(this,Activity1::class.java).apply {action = "actionA"putExtras(Bundle().apply {putString("content","hello")putString("sender","taylor")})startActivity(this)
}
复制代码
其中,apply
的定义如下:
//为泛型T对象添加新功能apply(),它接受一个lambda类型的参数block,且lambda调用的发起者是对象本身
public inline fun <T> T.apply(block: T.() -> Unit): T {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}//执行lambdablock()//返回调用者自身return this
}
复制代码
对于object.apply{lambda}
可以简单的理解为:在object对象上应用lambda操作,并且最终返回object对象本身。所以上述代码也可以写成更加紧凑的形式:
startActivity(Intent(this, Activity1::class.java).apply {action = "actionA"putExtras(Bundle().apply {putString("content", "hello")putString("sender", "taylor")})
})
复制代码
同一类型的预定义扩展函数还包括with
、let
、also
。它们的共同点是适用于 “对同一个对象做多次操作” 的场景 。它们的不同点总结如下:
函数 | 返回值 | 调用者角色 | 如何引用调用者 |
---|---|---|---|
also | 调用者本身 | 作为lambda参数 | it |
apply | 调用者本身 | 作为lambda接收者 | this |
let | lambda返回值 | 作为lambda参数 | it |
with | lambda返回值 | 作为lambda接收者 | this |
kotlin
中,发起调用扩展函数的那个对象,叫接收者对象。同理,发起调用lambda的对象叫做lambda接收者。- 可以将
also
的源码和apply
做对比,更好的理解他们调用者角色的差别:
//为泛型T对象添加新功能also(),它接受一个lambda类型的参数block,且对象是lambda的参数
public inline fun <T> T.also(block: (T) -> Unit): T {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}block(this)return this
}
复制代码
综合应用
“让 app 中所有被点击的 View 都带上缩放动画”。综合运用上述kotlin
知识点实现这个需求之前,先来看看java
是如何实现的:
- 先定义工具类,该工具类为传入的
View
分别设置触摸和单击监听器。在按下时播放动画,松手时反向播放动画。
public class ViewUtil {public static void addExtraAnimClickListener(View view, ValueAnimator animator, View.OnClickListener listener) {view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:animator.start();break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:animator.reverse();break;}//若返回true,则屏蔽了点击事件return false;}});view.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (listener != null) {listener.onClick(v);}}});}
}
复制代码
- 在界面中新建动画和点击响应逻辑并将它们传递给工具类
Button btn3 = findViewById(R.id.btn3);
//新建动画:变大
ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 1.2f);
animator.setDuration(100);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {Float value = ((Float) animation.getAnimatedValue());btn3.setScaleX(value);btn3.setScaleY(value);}
});
//点击响应逻辑
View.OnClickListener onClickListener = new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(Activity1.this, "spring anim", Toast.LENGTH_LONG).show();}
};
//应用工具类
ViewUtil.addExtraAnimClickListener(btn3, animator, onClickListener);
复制代码
不要眨眼,换kotlin
闪亮登场:
- 给View添加扩展函数
//扩展函数接收一个动画和一个点击响应逻辑(用lambda表示)
fun View.extraAnimClickListener(animator: ValueAnimator, action: (View) -> Unit) {setOnTouchListener { v, event ->when (event.action) {MotionEvent.ACTION_DOWN -> animator.start()MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> animator.reverse()}false}setOnClickListener { action(this) }
}
复制代码
- 应用扩展函数
btnSpringAnim.extraAnimClickListener(ValueAnimator.ofFloat(1.0f, 1.15f).apply {interpolator = AccelerateInterpolator()duration = 100addUpdateListener {btnSpringAnim.scaleX = it.animatedValue as FloatbtnSpringAnim.scaleY = it.animatedValue as Float}
}) { Toast.makeText(this, "spring anim", Toast.LENGTH_LONG).show() }
复制代码
btnSpringAnim
是一个Button
控件的id(只要装了kotlin插件,就不需要findViewById())as
保留字用于类型强制转换。- 是不是有一种 “白话文转文言文” 的感觉,
kotlin
凭借着极强的表达力用将近 1/3 的代码量完成了功能。
知识点总结
var
保留词用于声明变量,val
保留词用于声明常量。大多数情况下不需要显示指明变量类型,kotlin 具有类型推导能力,会根据上下文自动推断类型。fun
保留字用于声明函数。override
保留字表示重写父类方法或者实现接口中的抽象方法,与 java 不同的是,它必须显示出现在重写方法前( java 允许省略)。as
保留字用于类型强制转换。- kotlin 中类型是后置的,在变量名或函数参数列表后跟上
: 类型
就可以显示指定类型。 :
还用于继承类(取代extends
)、实现接口(取代implements
)。- 新建对象时不需要
new
,而是直接调用构造函数。 - 语句末尾不需要
;
但加上也不会有语法错误。 - kotlin 中类和方法默认是
final
的,他们不能被继承和重写。只有通过加上open
后才能被继承和重写。 - kotlin 中没有基本数据类型,而是用其对应的包装类表示。
- 给接口方法添加默认实现时不需要
default
关键字。 - kotlin 中的语句和表达式的唯一区别是:表达式有值,而语句没有。
- 如果函数体由单个表达式构成,可以省去花括号和return。
when
保留字用于取代switch-case
,而且它是一个表达式,返回值是命中分支中最后一表达式的值。- kotlin 引入了
property access syntax
,不再需要getter和setter方法,可以直接对属性赋值。 ?.
称为 安全调用运算符 ,只有当调用变量不为null
时,才会执行调用,否则整个表达式返回null
。这样就避免了防御式编程。?
置于类型之后表示这个类型的变量或返回值值可能为null
。- kotlin 使用扩展函数,可以在类体外给类新增方法。
- kotlin 预定了很多扩展函数,其中有一类适用于“对同一个对象做多次操作”。包括
also()
、apply()
、let()
、with()
。
最近开始学习 kotlin ,研读《Kotlin实战》的同时,在项目中加以运用。这个系列会不断地新增来自书本和实践中的新发现。希望对你能有所帮助~~
Kotlin基础:白话文转文言文般的Kotlin常识相关推荐
- Kotlin基础学习(一)—— Kotlin 简介
一.背景 2017年 的Google I/O大会上,Kotlin称为官方的Android开发语言. 发明公司:JetBrains(最负盛名的IDE创造者,包括Android Studio.Intell ...
- 第一章 kotlin基础知识
第一章 kotlin基础知识 文章目录 第一章 kotlin基础知识 前言 一.kotlin是什么? 二.kotlin基础知识 1.变量的声明 2.函数定义的几种方式 3.字符串与数字的转换 4.数组 ...
- Kotlin基础语法(上)
文章目录 Kotlin基础语法(下) Kotlin基础语法(上) 输出Hello world!!! 变量与输出 kotlin常见数据类型 变量的取值范围 kotlin函数 kotlin布尔类型 kot ...
- Kotlin基础学习 17
目录 1.Kotlin语言的过滤函数-filter 2.Kotlin语言的合并函数-zip 3.Kotlin语言的函数式编程 4.Kotlin语言的互操作性与可空性 5.单例模式 6.注解@Jvmna ...
- Kotlin学习(一):Kotlin基础知识
Kotlin学习(一):Kotlin基础知识 定义变量常量 在Kotlin中,定义变量时有以下几点与java不同: 位置不同:在 Kotlin 中,数据类型要放到变量后面,并且用冒号(:)分隔,这正好 ...
- Kotlin 基础学习
学! 原文:https://blog.csdn.net/CrazyApes/article/details/122091459 文章目录 Kotlin 线上编写 变量 lateinit延迟初始化 空安 ...
- Kotlin基础学习(1)
Kotlin基础学习(1) 本文主要讲解kotlin的部分基础知识,并不是全部基础. 提示:纯属个人理解,如有理解错误,欢迎留言指正批评. 一.Null检查机制 kotlin对于声明可为空的参数,使用 ...
- Kotlin 基础——Map集合详解
Kotlin基础--Map集合详解 一.声明和创建Map集合 二.使用Map的方法 三.遍历Map四种方式 四.可变的Map Kotlin的Map集合用于保存key-value对,其也被分为可变的和不 ...
- Kotlin Bootcamp 自学(2):Kotlin基础
Kotlin Bootcamp 自学(2):Kotlin基础 目录 Kotlin Bootcamp 自学(2):Kotlin基础 前言 运算符与数据类型 (Operators and Types) 数 ...
最新文章
- python3—廖雪峰之练习(三)
- iphone开发 如何在NSMutableDictionary中放入基本数据类型
- ROS2学习(七).ROS概念 - ROS客户端库(Ros Client Library)
- WinCE的网络驱动实现原理
- bobsmith电路阻抗原理_串联谐振原理全解析 - 赫兹电力
- 程序流程三控制,顺序控制,分支控制,循环控制综合练习题
- 系统集成项目管理工程师知识点集锦
- 请问smartadmin中如何只用其treeview 组件?
- android 红外遥控程序,基于Dragonboard 410c android系统红外遥控功能的实现方法
- 二分图判定 hdu5285 wyh2000 and pupil
- org.apache.flink.util.FlinkRuntimeException: Exceeded checkpoint tolerable failure threshold
- 【看表情包学Linux】文件描述符 | 重定向 Redirection | dup2 函数 | 缓冲区的理解 (Cache)
- Arduino与Proteus仿真实例-继电器驱动仿真
- TMS320F280049C 学习笔记11 控制率加速器 CLA 例程
- Android 10 Settings应用如何去掉一级菜单定时开关机
- Linux下安装钉钉
- 计算机网络教程试题库,计算机网络教程_复习题及答案.doc
- 苹果核”乔布斯不为人知的九件事
- 扫地机器人朋友圈文案_有关扫地机器人的文案
- 前端小项目-Thunder Raid(全民飞机大战)-html+css+js 含视频课程+全套代码
热门文章
- python 贴吧自动回复_python 几行代码实现自动回复功能
- python获取财务数据_「净利润增长率」使用python获取股票“净利润同比增长率”等“上市公司成长能力”数据 - seo实验室...
- 显示器点距 测试软件,液晶显示器常见、尺寸、分辨率、点距
- VC++如何通过代码自动弹出Windows系统的一些窗口(附源码)
- OneDrive和OneDrive for Business映射到本地网络驱动器
- 从开发零基础到登上Steam和Oculus:一个VR游戏开发者的自述
- COMP9021笔记
- 最新《VRay 2.0 for sketchup渲染教程》发布芹
- oracle 列转行 带逗号_oracle wm_concat 列转行 逗号分隔
- 自定义设置电脑屏保(.scr文件)