内容简介:这是刚接触新建对象不需要
这是 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{ @Override public 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
,则代码块中的最后一个表达式的值会被当做函数返回值,此时不需要 return
保留字:
//java public int add(int a, int b){ return a+b ; } //kotlin fun add(a: Int, b: Int): Int { a+b } 复制代码
如果函数体由单个表达式构成,可以省去花括号和return,并用赋值的 =
表示将表达式的值赋值给返回值:
fun add(a: Int, b: Int): Int = a+b 复制代码
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) } //执行lambda block() //返回调用者自身 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() { @Override public 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() { @Override public 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() { @Override public void onAnimationUpdate(ValueAnimator animation) { Float value = ((Float) animation.getAnimatedValue()); btn3.setScaleX(value); btn3.setScaleY(value); } }); //点击响应逻辑 View.OnClickListener onClickListener = new View.OnClickListener() { @Override public 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 = 100 addUpdateListener { btnSpringAnim.scaleX = it.animatedValue as Float btnSpringAnim.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实战》的同时,在项目中加以运用。这个系列会不断地新增来自书本和实践中的新发现。希望对你能有所帮助~~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ordering Disorder
Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99
The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!
RGB转16进制工具
RGB HEX 互转工具
Base64 编码/解码
Base64 编码/解码