转向Kotlin——类和接口
Posted Android机动车
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了转向Kotlin——类和接口相关的知识,希望对你有一定的参考价值。
类的声明
和Java没有什么两样,Kotlin中,类的声明也使用class关键字,如果只是声明一个空类,Kotlin和Java没有任何区别,不过定义类的其他成员,区别就很大了。
class MyClass{
}
类的构造器
构造器也叫构造方法,是类创建的必要元素。
1、主构造器
面向对象语言在定义类的时候,都需要至少制定一个构造方法,如果不指定构造器,编译器会默认生成一个不带任何参数的构造器,这是传统面向对象语言的做法。
Kotlin会有一些不一样的地方,在Kotlin中,类允许定义一个主构造器,和若干个第二构造器。主构造器是类头的一部分,紧跟在类名的后面,参数是可选的。如下代码定义了一个类,并指定了一个主构造器。
class Person constructor(name: String) {
}
如果主构造器没有任何注解,任何修饰,constructor可以省略:
class Person(name: String) {
}
上面的代码只是声明了主构造器,是在哪里实现构造器呢?如果是主构造器,需要在init代码块中进行初始化主构造器:
class Person(name: String) {
val myName = name
init {
println(name)
}
}
注意:主构造器中的参数不仅可以在init代码块中使用,还可以对类的属性进行初始化。
var和val也可以修饰主构造器参数,如果使用var,表示参数对于构造器来说是变量,在构造器内部可以对其进行操作和改变;如果使用val,表示该参数是常量,在构造器中不能修改它的值。但要注意的是,var修饰的参数,在主构造器中修改值后,并不会把修改后的值传到对象外面。
class Person(var name: String) {
init {
name="haha"
println(name)
}
}
2、第二构造器
Kotlin的类中,除了可以声明一个主构造器之外,还可以声明若干个第二构造器,第二构造器必须在类中声明,前面必须加constructor关键字。
class Person(var name: String) {
init {
name = "hello"+ name
println(name)
}
constructor(age: Int) : this("js") {
println(name + " " + age)
}
constructor(sex : Byte) :this(20){
println(name +" "+ sex)
}
}
明了主构造器,那么所有的第二构造器必须在声明的后面调用主构造器,或者通过另外一个第二构造器间接地调用主构造器。
当然,如果类中并没有声明主构造器,第二构造器后面可以不调用主构造器。
上面Person类中一共定义了三个构造器,就涉及到了构造器的重载,也就是一个类中拥有不同个参数和参数类型的构造器。
注意:主构造器中可以使用var和val修饰参数,但第二构造器中不能使用,也就意味着第二构造器中的参数都是只读的。
3、Kotlin的单例模式
我们只是大概了解以下Kotlin的单例模式如何书写,后面会详细介绍。
class Singleton private constructor() {
public var value: Singleton? = null
private object mHolder {
val INSTANCE = Singleton()
}
companion object Factory {
fun getInstance(): Singleton {
return mHolder.INSTANCE
}
}
}
4、函数中的默认参数
有很多变成语言是支持默认参数的,也就是在调用函数的时候不指定参数值,就会使用默认的参数值。Java不支持,但Kotlin是支持的,先看个例子:
class Class(param: Int, param1: String = "js") {
}
在创建Class对象时,可以只传第一个参数,第二个参数可以不传,如Class(5),其第二个参数默认为"js"。
由于Kotlin支持默认参数,所以没有必要非要定义一个没有参数的构造器,可以直接定义一个所有参数都有默认值的构造器。
5、创建类实例
创建Kotlin实例在之前已经用到过了。对于大都数面向对象的语言来说,创建类实例的时候都会用到new关键字,但Kotlin中不再需要,直接调用构造器即可,如MyClass()。
类成员
1、属性的基本用法
Java开发者对JavaBean一定特别熟悉,其实JavaBean就是一个普通的Javak类,关键在于对属性的get和set方法。当然Java可以直接使用public的成员变量来解决这个问题,但对于属性来说,不仅仅能读写其值,还需要对其进行二次加工,所以get/set也是必须的。
Kotlin中的属性语法,只有var/val和属性名时必须的,其他都是可选的。也就是说,Kotlin属性最简单的形式就是在类中定义一个变量(var)或常量(val),要引用属性,就像引用变量一样。
class Class{
var name:String="js"
val int:Int=2
fun pri(){
println("name=${name} int=${int}")
}
}
2、属性的get/set方法
因为Kotlin支持属性语法,所以并不需要对每个单独定义get和set方法。如果属性只是可读的(val),只需添加一个get方法,如果属性是读写的,添加get和set方法。g如果get/set方法只有一行代码,直接用=分隔即可,如果有多行代码,则z使用{}处理:
class Class {
var name: String
get() = name
set(value) {
name = value
}
val age: Int
get() = age
}
3、保存属性值的字段
Kotlin中可以使用filed标识符当作成员变量使用,也就是通过filed读写属性值:
class Class {
var name: String = "js"
get() = field
set(value) {
field = value
}
}
4、函数
Kotlin中,函数既可以在类外部定义,也可以在类的内部定义。如果是前者,是全局函数,如果是后者,是类成员函数。但无论定义在哪里,语法都是一样的。
说到构造器时,构造器支持默认参数值,实际上,函数也支持默认参数值。要注意的是,带默认值的参数必须是最后几个参数,也就是说,如果某个参数带有默认值,那么该参数后面的所有参数必须都有默认值:
class Class {
fun func(url: String, host: String = "www.baidu.com") {
}
}
但是如果带默认值的参数过多,在调的时候也会带来一些麻烦,如下:
class Class {
fun func(url: String, host: String = "www.baidu.com", name: String = "haha") {
}
}
当我想调用func方法,host参数使用默认值,而name参数自定义,就不得不在调用方法的时候将host参数显示地传"www.baidu.com"。为了解决这个问题,Kotlin允许使用命名参数传递参数值,所谓命名参数,就是在调用函数的时候指定形参名(host、name),这样就可以直接为指定的参数传值了,如:
Class().func("hh",name="hello")
如果传入函数的参数个数不固定,可以使用可变参数,可变参数用vararg关键字声明:
class Class {
fun func(url: String, host: String = "www.baidu.com", name: String = "haha") {
}
fun func2(vararg names: String) {
for (name in names) {
println(name)
}
}
}
很多时候,函数体中只有一行代码,用传统的写法就比较麻烦了,这时可以直接在函数声明后加等号(=),后面直接跟代码,这种方式可以省略函数返回值类型:
class Class {
var value: Int = 1
fun func(url: String, host: String = "www.baidu.com", name: String = "haha") {
}
fun func2(vararg names: String) {
for (name in names) {
println(name)
}
}
fun func3() = value
}
同时,在函数体内也可以定义函数,这种函数叫做本地函数,不再累赘。
5、嵌套类
所谓嵌套类,就是直接在n类内部再定义一个类。
class People {
class Student {
}
}
People.Student()
内部类还可以用inner声明,表示可以通过外部类的实例进行调用:
class People {
inner class Student {
}
}
People().Student()
修饰符
Kotlind的修饰符一共四个:private、protected、internal和public。
private:仅在类的内部可以调用;
protected:类似private,但在子类中也可以访问;
internal:模块中的任何类都可以调用;
public:任何类都可以访问。
如果不指定修饰符,默认全是public的,这些修饰符可以用在普通的类中,也可以用在构造器中。
类的继承
1、如何继承
与Java不同,Kotlin类的继承需要使用冒号(:),而Java使用extends。注意,冒号后面需要调用父类的构造器。
Kotlin和Java一样,都是单继承的,也就是说,一个Kotlin类只能有一个父类。要注意的是,Kotlin类默认是final的,也就是不允许继承的,需要显示地用open关键字声明,表示此类可以被继承。
open class School {
}
class MiddleSchool : School() {
}
2、重写方法
Kotlin中不仅类默认是不可以被继承的,连方法默认也是不可以重写的。因此,如果要在子类中重写方法啊,那么父类的对应方法必须用open修饰,而且要在子类重写的方法前面加override关键字:
open class School {
open fun func() {
}
}
class MiddleSchool : School() {
override fun func() {
}
}
如果一个方法已经被override修饰了,那么这个方法已经就被重写了,依然可以被它的子类所重写。
3、重写属性
属性的重写与方法类似,被重写的属性也必须用open修饰,子类属性必须用override修饰。不过要注意,val属性可以被重写为var属性,但反过来不可以:
open class School {
open val name: String = "School"
open fun func() {
}
}
class MiddleSchool : School() {
override var name: String = "MiddleSchool"
override fun func() {
}
}
接口
接口是另一个重要的面向对象元素,用于制定规范,强调对象是否具有某个功能。
Kotlin与Java类似,使用interface声明接口,一个类可以实现多个接口,实现的方法和类继承相同,而且,接口中的属性和方法都是open的。
interface MyInterface {
fun func()
fun func2(): String {
return "js"
}
}
class MyClass : MyInterface {
override fun func() {
}
}
上述代码中可以看出:实现接口与继承父类类似,使用冒号(:),但后面不是调用构造方法,而是是指跟接口名;Kotlin中的接口的方法,允许包含默认方法体,对于这样的额方法,子类实现接口时不一定必须实现该方法。
抽象类
抽象类和接口非常相似,抽象类不能被实例化,需要abstract关键字声明,抽象类实现接口后,接口中没有函数体的函数可以不重写,接口中的这些方法自动被继承到子类中,称为抽象方法:
abstract class MyAbsClass{
abstract fun f()
}
抽象方法没必要用open声明,因为抽象类本身就是可以被继承的。
小结
Kotlin中的类e和接口与Java中的本质上没有什么两样,只不过Kotlin为了体现差异,加入了一些语法糖,如接口允许函数带函数体,支持属性,不支持静态方法等。我们需要慢慢去熟悉它。
以上是关于转向Kotlin——类和接口的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin学习之旅解决错误:kotlin.NotImplementedError: An operation is not implemented: Not yet implemented(代码片段