内容简介:这是刚接触新建对象不需要
这是 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实战》的同时,在项目中加以运用。这个系列会不断地新增来自书本和实践中的新发现。希望对你能有所帮助~~
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。