5.3 Kotlin 中的操作符重载汇总表 与 可见性修饰符总结

本篇的知识点会在《 3.2.2 在 Kotlin 中实现 RecyclerView 及其点击事件》中被用到,到时可以回头进行查阅。

一、操作符重载

就像其他每种语言一样,Kotin有一些固定数量象征性的操作符,这里预定义了一些操作符执行一定的操作,我们可以在任何类中很容易地使用它们。比如典型的加(+),减(-),乘(),除(/)*,而且还有很多其它的。

类似Java这样的一些语言,这些操作符被限制在一些特定的数量类型上,且没有方法让其他类型数据使用这些操作符。不过Kotlin有这种方案:它有一些预定义的操作符,但是我们能够为任意数据类型而重载它们。方法也很简单,那就是创建一个函数,函数名为保留的操作符关键字,这样就可以让这个操作符的行为映射到这个函数,重载这些操作符可以增加代码可读性和简洁性。

1、操作符表

这里你可以看见一系列包括操作符和对应方法的表,对应方法必须在指定的类中通过各种可能性被实现:

一元操作符
操作符 函数
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
a++ a.inc()
a-- a.dec()
二元操作符
操作符 函数
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.mod(b)
a..b a.rangeTo(b)
a in b a.contains(b)
a !in b !a.contains(b)
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.modAssign(b)
数组操作符
操作符 函数
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ..., i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ..., i_n] = b a.set(i_1, ..., i_n, b)
等于操作符
操作符 函数
a == b a?.equals(b) ?: b === null
a != b !(a?.equals(b) ?: b === null)

相等操作符有一点不同,为了达到正确合适的相等检查做了更复杂的转换,因为要得到一个确切的函数结构比较,不仅仅是指定的名称,方法必须要如下准确地被实现:

operator fun equals(other: Any?): Boolean

操作符===和!==用来做身份检查(它们分别是Java中的==和!=),并且它们不能被重载。

激活(invoking)函数调用
方法 调用
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ..., i_n) a.invoke(i_1, ..., i_n)

二、操作符重载的例子

1、onBindViewHolder中的使用

你可以想象,Kotlin List是实现了数组操作符的,所以我们可以像Java中的数组一样访问List的每一项。除此之外:在可修改的List中,每一项也可以用一个简单的方式被直接设置:

val x = myList[2]
myList[2] = 4

我们这里给出一个叫TestList的数据类,它是由很多其他额外的信息组成的,有趣的是我们可以直接访问它的每一项而不是请求内部的list得到某一项。做一个完全不相关的事情,我要去实现一个size()方法,它能稍微能简化一点当前的Adapter:

data class TestList(val city: String, val country: String, val dailyTest: List<Test>) {
    operator fun get(position: Int): Test = dailyTest[position]
    fun size(): Int = dailyTest.size
}

这样会使我们的onBindViewHolder更简单一点(后面的文章《 3.2.2 在 Kotlin 中实现 RecyclerView 及其点击事件》会继续讲解相关内容):

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    with(weekTest[position]) {
        holder.textView.text = "$date - $description - $high/$low"
    }
}

当然还有getItemCount()方法:

override fun getItemCount(): Int = weekTest.size()
2、扩展函数中的操作符

我们不需要去扩展我们自己的类,但是我需要去使用扩展函数扩展我们已经存在的类来让第三方的库能提供更多的操作。几个例子,我们可以去像访问List的方式去访问ViewGroup的view:

operator fun ViewGroup.get(position: Int): View = getChildAt(position)

现在真的可以非常简单地从一个ViewGroup中通过position得到一个view:

val container: ViewGroup = find(R.id.container)
val view = container[2]

如果你暂时看不懂其实没关系,这里我们所说的会在之后的章节中全部讲解到,点击关注即可。

三、可见性修饰符

和Java中的一样,Kotlin中的类、对象、接口、构造函数、属性以及它们的 setter 方法都可以有可见性修饰词,并且也是类似的四个:private、protected、internal 以及 public。但是Kotlin中这些修饰符是与我们Java中的使用是有些不同的,比如在这个语言中默认的修饰符是public,这就节约了我们很多的时间、字符和绳命,下面我们来详细看一下。

1、修饰符

(1)private

private 修饰符是我们使用的最具有限制性的修饰符,它表示它只能被自己所在的文件可见。所以如果我们给一个类声明为private,我们就不能在定义这个类之外的文件中使用它。

另一方面,如果我们在一个类里面使用了private修饰符,那访问权限就被限制在这个类里面了,甚至是继承这个类的子类也都不能使用它。所以类、对象、接口……(也就是包成员)如果被定义为private,那么它们只会对被定义所在的文件可见,如果被定义在了类或者接口中,那它们只对这个类或者接口可见。

(2)protected

这个修饰符的存在就是只能修饰类或者接口中的成员上,一个包成员不能被定义为protected,包级属性是不能修饰的。而定义在一个成员中,就与Java中的方式一样了:它可以被成员自己和继承它的成员可见,比如类和它的子类。

(3)internal

在Kotlin中就因为有了包级的属性(而java包下面只能是类或者接口等,所以Kotlin就可以很随意的去定义变量、类、接口、函数等),所以才多了个internal修饰符。而为了区别于protected,被internal修饰的类、函数或者接口可以在同一module下访问,除此之外如果internal修饰的是类内部的成员,那这个成员就成了只有这个类内部能访问的成员,比如private修饰的类,就只能在类的内部访问。

也就是说,如果是一个定义为internal的包成员的话,对所在的整个module可见。如果它是一个其它领域的成员,它就需要依赖那个领域的可见性了。比如,如果我们写了一个private类,那么它的internal修饰的函数的可见性就会限制与它所在的这个类的可见性。总之,我们可以访问同一个module中的internal修饰的类,但是不能访问其它module的。

什么是module?

根据Jetbrains的定义,一个module应该是一个单独的功能性的单位,它应该是可以被单独编译、运行、测试、debug的。根据我们项目不同的模块,可以在Android Studio中创建不同的module。在Eclipse中,这些module可以认为是在一个workspace中的不同的project。

(4)public

你应该可以猜想到,这是最没有限制的修饰符。而且这个修饰符与java最大的不同是,它在Kotlin中是默认的,也就是我们不声明的属性会默认成为public。当然了它只限制于它的领域,一个定义为public的成员被包含在一个private修饰的类中,这个成员在这个类以外也是不可见的。

2、构造器与代码润色

所有构造函数默认都是public的,它们类是可见的,可以被其它地方使用,不过我们也可以使用这个语法来把构造函数修改为private:

class C private constructor(a: Int) { ... }

如果我们在编写类的时候,你觉得某些属性因为是什么原因不能对别人可见,那就把它定义为private:

class RequestForecastCommand(private val zipCode: String)

上面这段代码所作的事情就是创建了一个不可修改的属性zipCode,它的值我们只能去得到,不能去修改它,所以这个不大的改动让代码看起来更加清晰。

而且在Kotlin中,我们不需要去指定一个函数的返回值类型,它可以让编译器推断出来。举个省略返回值类型的例子:

data class TestList(...) {
    fun get(position: Int) = dailyTest[position]
    fun size() = dailyTest.size()
}

我们可以省略返回值类型的典型情景是:当我们要给一个函数或者一个属性赋值,而又不需要去写代码块去实现的时候。

感谢优秀的你跋山涉水看到了这里,欢迎关注下让我们永远在一起!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容