Kotlin——最详细的接口使用、介绍
在上一章节中,详细的类(class)
做了一个实例讲解,提到了类(class)
的实例化、构造函数、声明、实现方式、和Java
中类的区别等。但是对于Kotlin
中的类的使用还远远不止那些。并且在上文中提到了关于类的类别。故而这篇文章就详细说一说Kotlin
中的枚举类(Enum
)、接口类(Interface
)的使用。
如果还对Kotlin
中的类还没有一个清晰的概念及认识的朋友请阅读我的上一篇博文:
目录
一、枚举类
1.1、声明方式及枚举常量
- 关键字:
enum
- 枚举常量:即枚举类下的对象,每个枚举类包含0个到多个枚举常量。
1.1.1、声明
enum
关键字在类头中的class
关键字前面
声明格式:
enum class 类名{
...
}
1.1.2、枚举常量
枚举类中的每一个枚举常量都是一个对象,并且他们之间用逗号分隔。
例:
/**
* 例:关于一个网络请求结果的枚举类
*/
enum class State{
/*
NORMAL : 正常
NO_DATA : 数据为空
NO_INTERNET : 网络未连接
ERROR : 错误
OTHER : 其他
*/
NORMAL,NO_DATA,NO_INTERNET,ERROR,OTHER
}
1.1.3、访问枚举常量
- 不需要实例化枚举类就可以访问枚举常量
使用方式为:
枚举类名.枚举常量.属性
通过上面例子来实例讲解:
// 使用中缀符号访问枚举常量
State.NORMAL.name
State.NO_DATA.name
State.NO_INTERNET.name
State.ERROR.name
State.OTHER.name
这里只是让大家明白怎样去访问一个枚举常量。没有讲解到枚举常量的使用。枚举常量的使用请大家耐心的看下去。在下面会详细介绍怎样去使用它。
1.2 、枚举常量的初始化
- 因为每一个枚举都是枚举类的实例,所以他们可以是初始化过的。
例:
enum class Color(var argb : Int){
RED(0xFF0000),
WHITE(0xFFFFFF),
BLACK(0x000000),
GREEN(0x00FF00)
}
1.3、枚举常量的匿名类
- 要实现枚举常量的匿名类,则必须提供一个抽象方法(必须重写的方法)。且该方法定义在枚举类内部。而且必须在枚举变量的后面。
- 枚举变量之间使用逗号(
,
)分割开。但是最后一个枚举变量必须使用分号结束。不然定义不了抽象方法。- 在上面已经说过,每一个枚举常量就是一个对象。
例:
fun main(args: Array<String>) {
ConsoleColor.BLACK.print()
}
enum class ConsoleColor(var argb : Int){
RED(0xFF0000){
override fun print() {
println("我是枚举常量 RED ")
}
},
WHITE(0xFFFFFF){
override fun print() {
println("我是枚举常量 WHITE ")
}
},
BLACK(0x000000){
override fun print() {
println("我是枚举常量 BLACK ")
}
},
GREEN(0x00FF00){
override fun print() {
println("我是枚举常量 GREEN ")
}
};
abstract fun print()
}
输出结果为:
我是枚举常量 BLACK
1.4、枚举类的使用
- 每个枚举常量都包含两个属性:
name(枚举常量名)
和ordinal(枚举常量位置)
- 提供了
values()
和valueOf()
方法来检测指定的名称与枚举类中定义的任何枚举常量是否匹配。- 自
Kotlin 1.1
起,可以使用enumValues<T>()
和enumValueOf<T>()
函数以泛型的方式访问枚举类中的常量。
1.4.1、访问枚举变量属性
例:
fun main(args: Array<String>) {
println("name = " + Color.RED.name + "\tordinal = " + Color.RED.ordinal)
println("name = " + Color.WHITE.name + "\tordinal = " + Color.WHITE.ordinal)
println("name = " + Color.BLACK.name + "\tordinal = " + Color.BLACK.ordinal)
println("name = " + Color.GREEN.name + "\tordinal = " + Color.GREEN.ordinal)
}
enum class Color(var argb : Int){
RED(0xFF0000),
WHITE(0xFFFFFF),
BLACK(0x000000),
GREEN(0x00FF00)
}
输出结果为:
name = RED ordinal = 0
name = WHITE ordinal = 1
name = BLACK ordinal = 2
name = GREEN ordinal = 3
1.4.2、使用enumValues<T>()
和 enumValueOf<T>()
访问
例: 枚举类还是上面例子中的Color
类
println(enumValues<Color>().joinToString { it.name })
println(enumValueOf<Color>("RED"))
输出结果为:
RED, WHITE, BLACK, GREEN
RED
1.4.3、使用valueOf()
和values()
检测
例:
println(Color.valueOf("RED"))
println(Color.values()[0])
println(Color.values()[1])
println(Color.values()[2])
println(Color.values()[3])
输出结果为:
RED
RED
WHITE
BLACK
GREEN
其中,若使用Color.valueOf("不存在的枚举常量")
,则会抛出IllegalArgumentException
异常,即枚举变量不存在。若使用Color.values()[大于枚举常量位置]
,则会抛出下标越界异常。
1.5、枚举类的源码分析
即
Enum.kt
这个源文件。
在这里我大致的说明一下这个源文件的方法、属性等。有兴趣的可以去看看这个源文件。其实里面也没几个方法。
1.5.1、默认实现了companion object {}
这也是我们访问枚举常量无需实例化枚举类的原因。
1.5.2、仅提供了两个属性
- 即我们上面用到的枚举常量名称(
name
)和枚举常量位置(ordinal
)
贴上这两个属性的源码:
/**
* Returns the name of this enum constant, exactly as declared in its enum declaration.
*/
public final val name: String
/**
* Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant
* is assigned an ordinal of zero).
*/
public final val ordinal: Int
1.5.3、实现了Comparable
接口
- 这也是我们能获取枚举常量位置的原因。
这是Enum.kt
源文件。让大家看看它实现了Comparable
接口
public abstract class Enum<E : Enum<E>>(name: String, ordinal: Int): Comparable<E>{
...
}
再来看看Comparable.kt
里面做了些什么。其实里面就提供了一个方法罢了...
public interface Comparable<in T> {
/**
* Compares this object with the specified object for order. Returns zero if this object is equal
* to the specified [other] object, a negative number if it's less than [other], or a positive number
* if it's greater than [other].
*/
public operator fun compareTo(other: T): Int
}
关于枚举类的讲解就写到这里了。不清楚的可以多看看文章,或者看看源码、官方文档等等。当然,自己按照我的例子去敲一遍代码也是非常不错的。
二、接口类
2.1、接口的基础使用
2.1.1、声明
关键字:
interface
定义格式:
interface 接口名{
...
}
2.1.2、用法
- 关键字:冒号(
:
),这一点是和Java
不同的。Java
中使用接口使用的是implements
关键字- 在
Kotlin
中冒号(:
)使用的地方很多:
- 用于变量的定义
- 用于继承
- 用于接口
- 方法的返回类型声明
使用格式:
class 类名 : 接口名{
// 重写的接口函数、属性等
...
}
2.1.3、举例说明
fun main(args: Array<String>) {
// 类的初始化
var demo = Demo1()
demo.fun1()
}
/**
* 我定义的接口
*/
interface Demo1Interface{
// 定义的方法
fun fun1()
}
/**
* 接口的实现类
*/
class Demo1 : Demo1Interface{
override fun fun1() {
println("我是接口中的fun1方法")
}
}
输出结果为:
我是接口中的fun1方法
2.2、接口中的方法使用
- 不带结构体的函数可以省略大括号,且不用强制重写带结构体的函数就可以直接调用。不太明白也没关系,下面的代码中都有注释。
例:
fun main(args: Array<String>) {
var demo = Demo2()
demo.fun1()
demo.fun2(5)
println(demo.fun3(10))
println(demo.fun4())
//可以不重写该方法直接调用
demo.fun5()
}
interface Demo2Interface{
/**
* 定义一个无参数无返回值的方法
*/
fun fun1()
/**
* 定义一个有参数的方法
*/
fun fun2(num: Int)
/**
* 定义一个有参数有返回值的方法
*/
fun fun3(num: Int) : Int
// 下面的两个方法是有结构体, 故可以不重写
/**
* 定义一个无参数有返回值的方法
*/
fun fun4() : String{
return "fun4"
}
/**
* 定义一个无结构体函数,大括号是可以省略的
*/
fun fun5(){
// 如果函数中不存在表达式,大括号可以省略。
// 如fun1一样
}
}
class Demo2 : Demo2Interface{
override fun fun1() {
println("我是fun1()方法")
}
override fun fun2(num: Int) {
println("我是fun2()方法,我的参数是$num")
}
override fun fun3(num: Int): Int {
println("我是fun3()方法,我的参数是$num,并且返回一个Int类型的值")
return num + 3
}
override fun fun4(): String {
println("我是fun4()方法,并且返回一个String类型的值")
/*
接口中的fun4()方法默认返回”fun4“字符串.
可以用super.fun4()返回默认值
也可以不用super关键字,自己返回一个字符串
*/
return super.fun4()
}
/*
接口中的fun5()带有结构体,故而可以不用重写,
fun4()同样
*/
// override fun fun5() {
// super.fun5()
// }
}
输出结果为:
我是fun1()方法
我是fun2()方法,我的参数是5
我是fun3()方法,我的参数是10,并且返回一个Int类型的值
13
我是fun4()方法,并且返回一个String类型的值
fun4
2.3、接口中的属性使用
- 在接口中申明属性。接口中的属性要么是抽象的,要么提供访问器的实现。接口属性不可以有后备字段。而且访问器不可以引用它们。
2.3.1、作为抽象
- 即重写属性的时候是在实现类的类参数中。这也是用代码提示去重写的实现方法
例:
fun main(args: Array<String>) {
var demo = Demo3(1,2)
println(demo.sum())
}
interface Demo3Interface{
val num1: Int
val num2 : Int
}
class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface{
fun sum() : Int{
return num1 + num2
}
}
输出结果为:
3
2.3.2、作为访问器
即手动方式去实现重写,并提供get()方法
例:
fun main(args: Array<String>) {
println(demo.result())
// 在这里也可以改变接口属性的值
demo.num4 = 10
println(demo.result())
}
interface Demo3Interface{
// 声明比那俩和提供默认值
// 注意: val num3: Int = 3 这种方式不提供,为直接报错的
val num3: Int
get() = 3
val num4: Int
}
class Demo3(override val num1: Int, override val num2: Int) : Demo3Interface{
// 提供访问器实现
override val num3: Int
get() = super.num3
// 手动赋值
override var num4: Int = 4
fun result() : Int{
return num3 + num4
}
}
输出结果为:
7
13
2.4、接口的冲突问题解决
- 该问题是指当我们在父类中声明了许多类型,有可能出现一个方法的多种实现。
例:
fun main(args: Array<String>) {
// 类的初始化
val demo = Demo4()
demo.fun1()
demo.fun2()
}
interface Demo4InterfaceOne{
fun fun1(){
println("我是Demo4InterfaceOne中的fun1()")
}
fun fun2(){
println("我是Demo4InterfaceOne中的fun2()")
}
}
interface Demo4InterfaceTwo{
fun fun1(){
println("我是Demo4InterfaceTwo中的fun1()")
}
fun fun2(){
println("我是Demo4InterfaceTwo中的fun2()")
}
}
class Demo4 : Demo4InterfaceOne,Demo4InterfaceTwo{
override fun fun1() {
super<Demo4InterfaceOne>.fun1()
super<Demo4InterfaceTwo>.fun1()
}
override fun fun2() {
super<Demo4InterfaceOne>.fun2()
super<Demo4InterfaceTwo>.fun2()
}
}
说明:Demo4
实现了Demo4InterfaceOne
和Demo4InterfaceTwo
两个接口,而两个接口中都存在两个相同方法名的方法。因此编译器不知道应该选哪个,故而我们用super<接口名>.方法名
来区分。
三、 总结
我个人是从事Android
开发的,以前用Java
语言开发APP
时因为考虑到手机性能的问题几乎用不到枚举的。因为枚举太消耗内存了。当然用Kotlin
语言开发Android
项目中是否要用到枚举去便利去解决一些问题,此待小生自己研究。但是开发服务端项目时,一些问题用枚举是非常便利性的。
对于接口类来说,它在一个项目中是重中之重的,对于项目中代码的耦合性、便利性都能用接口类去实现一个良好的项目架构,对项目后期的维护或者说重构来说,都能有良好的体现。可能很多Java
开发者都深有体会
如果各位大佬看了之后感觉还阔以,就请各位大佬随便star
一下,您的关注是我最大的动力。
我的个人博客:Jetictors
我的掘金:Jetictors
Github:Jetictors
欢迎各位大佬进群共同研究、探索
QQ群号:497071402
Kotlin——最详细的接口使用、介绍的更多相关文章
- 微信内置浏览器私有接口WeixinJSBridge介绍(转)
这篇文章主要介绍了微信内置浏览器私有接口WeixinJSBridge介绍,本文讲解了发送给好友.分享函数.隐藏工具栏.隐藏三个点按钮等功能,需要的朋友可以参考下 微信网页进入,右上角有三个小点,没错, ...
- 微信内置浏览器私有接口WeixinJSBridge介绍
原文地址:http://www.3lian.com/edu/2015/05-25/216227.html 这篇文章主要介绍了微信内置浏览器私有接口WeixinJSBridge介绍,本文讲解了发送给好友 ...
- 转载:kafka c接口librdkafka介绍之二:生产者接口
转载:from:http://www.verydemo.com/demo_c92_i210679.html 这个程序虽然我调试过,也分析过,但是没有记录笔记,发现下边这篇文章分析直接透彻,拿来借用,聊 ...
- 引擎基本服务接口API介绍
Slickflow.NET 开源工作流引擎基础介绍(一) -- 引擎基本服务接口API介绍 https://www.cnblogs.com/slickflow/p/4807227.html 工作流术语 ...
- Java + selenium window()接口方法介绍
在浏览器启动的代码中,有一段关于window接口的调用,这篇文章就是来解释介绍这个接口的.代码如下 driver.manage().window().maxmize(); window接口主要是用来控 ...
- 超详细,多图文介绍redis集群方式并搭建redis伪集群
超详细,多图文介绍redis集群方式并搭建redis伪集群 超多图文,对新手友好度极好.敲命令的过程中,难免会敲错,但为了截好一张合适的图,一旦出现一点问题,为了好的演示效果,就要从头开始敲.且看且珍 ...
- Kotlin——最详细的数据类型介绍
任意一种开发语言都有其数据类型,并且数据类型对于一门开发语言来说是最基本的构成,同时也是最基础的语法.当然,kotlin也不例外.kotlin的数据类型和Java是大致相同的,但是他们的写法不同,并且 ...
- Kotlin——最详细的抽象类(abstract)、内部类(嵌套类)详解
如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索QQ群号:497071402 进入正题 在前面几个章节中,详 ...
- Kotlin——最详细的操作符与操作符重载详解(上)
本篇文章为大家详细的介绍Koltin特有的操作符重载.或许对于有编程经验的朋友来说,操作符这个词绝对不陌生,就算没有任何编辑基础的朋友,数学中的算数运算符也绝不陌生.例如(+.-.*./.>.& ...
随机推荐
- .Net45下HttpClient的几个缺陷
前言 最近在写WebClientApi这个组件,底层使用HttpClient,发现HttpClient有许多低级的错误,使用者一不小心就可能会正常的去调用它的这些错误,得不到预期的结果.本文我把我认为 ...
- panda库2
>>> a=pd.Series([1,2],index=['a','b']) >>> a a 1 b 2 dtype: int64 >>> b=p ...
- Hibernate中cascade属性的区别
xml对于集合的级联操作属性cascade的取值可以是: none: 不级联操作,默认为none save-update:针对的是当对当前对象进行save或update操作时,要对想关联的对象进行sa ...
- 系统学习java高并发系列二
转载请注明原创出处,谢谢! 什么是线程? 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程 ...
- AngularJS 框架
AngularJS 通过 指令 扩展了 HTML,且通过 表达式 绑定数据到 HTML. [Angular JS表达式] 1.Angular JS使用双{{}}绑定方式.用于将表达式的内容输出到页面 ...
- java中Set类接口的用法
在Java中使用Set,可以方便地将需要的类型,以集合类型保存在一个变量中.主要应用在显示列表. Set是一个不包含重复元素的collection.更确切地讲,set 不包含满足 e1.equals( ...
- .NET Excel导出方法及其常见问题详解
摘要:.NET Excel导出方法及其常见问题详解. 一.Excel导出的实现方法 在.net 程序开发中,对于Excel文件的导出我们一共有三种导出方式: 利用文件输出流进行读写操作 这种方式的导出 ...
- AngularJS 1.3中的一次性数据绑定(one-time bindings)
点击查看AngularJS系列目录 谈谈AngularJS 1.3中的一次性数据绑定(one-time bindings) 不久之前,AngularJS 1.3版本正式发布,其中添加了很多的性特性,同 ...
- asp.net core后台系统登录的快速构建
登录流程图 示例预览 构建步骤 当然,你也可以直接之前前往coding仓库查看源码,要是发现bug记得提醒我啊~ LoginDemo地址 1. 首先你得有一个项目 2. 然后你需要一个登录页面 完整L ...
- 基于FPGA的肤色识别算法实现
大家好,给大家介绍一下,这是基于FPGA的肤色识别算法实现. 我们今天这篇文章有两个内容一是实现基于FPGA的彩色图片转灰度实现,然后在这个基础上实现基于FPGA的肤色检测算法实现. 将彩色图像转化为 ...