《Kotlin核心编程》 ——3.2.2 可见性修饰符

举报
华章计算机 发表于 2020/02/21 22:39:44 2020/02/21
【摘要】 本节书摘来自华章计算机《Kotlin核心编程》 —— 书中第3章,第3.2.2节,作者是水滴技术团队 。

3.2.2 可见性修饰符

除了限制类修饰符之外,还有一种修饰符就是可见性修饰符。下面我们就来看看Kotlin中的可见性修饰符。

若你想要指定类、方法及属性的可见性,那么就需要可见性修饰符。Kotlin中的可见性修饰符也与Java中的很类似。但也有不一样的地方,主要有以下几点:

1)Kotlin与Java的默认修饰符不同,Kotlin中是public,而Java中是default。

2)Kotlin中有一个独特的修饰符internal。

3)Kotlin可以在一个文件内单独声明方法及常量,同样支持可见性修饰符。

4)Java中除了内部类可以用private修饰以外,其他类都不允许private修饰,而Kotlin可以。

5)Kotlin和Java中的protected的访问范围不同,Java中是包、类及子类可访问,而Kotlin只允许类及子类。

我们首先来看默认修饰符。很多时候,你在写类或者方法的时候都会省略它的修饰符,当然,在Java中我们很自然地会给类加上public修饰符,因为大多数类都可能需要在全局访问。而Java的默认修饰符是default,它只允许包内访问,但是我们很多时候厌烦了每次都要加public,虽然通常编辑器会自动帮我们加上,但是总觉得这是一个多余的声明。所以,Kotlin可能考虑了这方面因素,将可见修饰符默认指定为public,而不需要显式声明。

上面说到了Java中默认修饰符是default,它的作用域是包内可访问。那么Kotlin中有类似的修饰符吗?

Kotlin中有一个独特的修饰符internal,和default有点像但也有所区别。internal在Kotlin中的作用域可以被称作“模块内访问”。那么到底什么算是模块呢?以下几种情况可以算作一个模块:

一个Eclipse项目

一个Intellij IDEA项目

一个Maven项目

一个Grandle项目

一组由一次Ant任务执行编译的代码

总的来说,一个模块可以看作一起编译的Kotlin文件组成的集合。那么,Kotlin中为什么要诞生这么一种新的修饰符呢?Java的包内访问不好吗?

Java的包内访问中确实存在一些问题。举个例子,假如你在Java项目中定义了一个类,使用了默认修饰符,那么现在这个类是包私有,其他地方将无法访问它。然后,你把它打包成一个类库,并提供给其他项目使用,这时候如果有个开发者想使用这个类,除了copy源代码以外,还有一个方式就是在程序中创建一个与该类相同名字的包,那么这个包下面的其他类就可以直接使用我们前面的定义的类。伪代码如下:

package com.dripower

 

/**

定义的第三方类库代码

 */

class TestDefault {

    ...

}

该类默认只允许com.dripower的包内可见,但是我们在项目中可以这么做:

package com.dripower

 

/**

自身工程创建com.dripower

 */

class Test {

    TestDefault td = new TestDefault();

    ...

}

这样我们便可以直接访问该类了。

而Kotlin默认并没有采用这种包内可见的作用域,而是使用了模块内可见,模块内可见指的是该类只对一起编译的其他Kotlin文件可见。开发工程与第三方类库不属于同一个模块,这时如果还想使用该类的话只有复制源码一种方式了。这便是Kotlin中internal修饰符的一个作用体现。

在Java程序中,我们很少见到用private修饰的类,因为Java中的类或方法没有单独属于某个文件的概念。比如,我们创建了Rectangle.java这个文件,那么它里面的类要么是public,要么是包私有,而没有只属于这个文件的概念。若要用private修饰,那么这个只能是其他类的内部类。而Kotlin中则可以用private给单独的类修饰,它的作用域就是当前这个Kotlin文件。比如:

package com.dripower.car

 

class BMWCar(val name: String) {

    private val bMWEngine = Engine("BMW")

    fun getEngine(): String {

        return bMWEngine.engineType()//error:Cannot access'enging Type': it is Protected in Engine

    }

}

 

private class Engine(val type: String) {

    fun engineType(): String {

        return "the engine type is $type"

    }

}

除了private修饰符的差别,Kotlin中的protected修饰符也与Java有所不同。Java中的protected修饰的内容作用域是包内、类及子类可访问,而在Kotlin中,由于没有包作用域的概念,所以protected修饰符在Kotlin中的作用域只有类及子类。我们对上面的代码稍加修改:

package com.dripower.car

 

class BMWCar(val name: String) {

    private val bMWEngine = Engine("BMW")

    fun getEngine(): String {

        return bMWEngine.engineType()//error:Cannot access'enging Type'it is Protected in Engine

    }

}

 

private open class Engine(val type: String) {

    protected open fun engineType(): String {

        return "the engine type is $type"

    }

}

 

private class BZEngine(type: String) : Engine(type) {

    override fun engineType(): String {

        return super.engineType() 

    }

}

我们可以发现同一包下的其他类不能访问protected修饰的内容了,而在子类中可以。

总结一下,可见性修饰符在Kotlin与Java中大致相似,但也有自己的很多特殊之处。这些可见性修饰符比较如表3-2所示。

表3-2 Kotlin与Java的可见性修饰符比较

image.png

 

在了解了Kotlin中的可见修饰符后,我们来思考一个问题:前面已经讲解了为什么要诞生internal这个修饰符,那么为什么Kotlin中默认的可见性修饰符是public,而不是internal呢?

关于这一点,Kotlin的开发人员在官方论坛进行了说明,这里我做一个总结:Kotlin通过分析以往的大众开发的代码,发现使用public修饰的内容比其他修饰符的内容多得多,所以Kotlin为了保持语言的简洁性,考虑多数情况,最终决定将public当作默认修饰符。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。