Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Kotlin
Code

Kotlin从零开始:课程和对象

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Kotlin From Scratch.
Kotlin From Scratch: Advanced Functions
Kotlin From Scratch: Advanced Properties and Classes

Chinese (Simplified) (中文(简体)) translation by Zhang Xiang Liang (you can also view the original English article)

Kotlin是一种编译为Java字节码的现代编程语言。它是免费的,  开源,并有望使Android开发更有趣。

在  前面的文章中,您学习了Kotlin中函数的高级用法,例如扩展函数,闭包,高阶函数和内联函数。 

在本文中,您将通过了解Kotlin中的面向对象编程入门:构造函数和属性,转换以及Kotlin变得更加简单的更高级的类功能。 

1. 类

类是一个程序单元,将功能和数据分组在一起以执行一些相关的任务。我们使用class关键字(类似于Java)在Kotlin中声明一个类。 

前面的代码是最简单的类声明 - 我们只创建了一个名为的空类  Book。即使它不包含使用其默认构造函数的主体,我们仍然可以实例化此类。

正如你可以在上面的代码中看到的那样,我们没有使用new关键字来实例化这个类,就像在其他编程语言中那样。 new在Kotlin中不是关键字。这使得我们的源代码在创建类实例时变得简洁。但请注意,在Java中实例化Kotlin类将需要new关键字。  但请注意,在Java中实例化Kotlin类将需要new关键字。 

类构造函数和属性

让我们来看看如何为我们的类添加构造函数和属性。但首先,让我们看一下Java中的典型类:

看看我们Book 上面的模型类,我们有以下几点:

  • 两个领域:title和isbn
  • 一个构造函数
  • 这两个领域的getter和setter(幸运的是,IntelliJ IDEA可以帮助我们生成这些方法)

现在让我们看看我们如何在Kotlin中编写前面的代码:

一个相当整洁的类!我们现在已经将代码行数从20减少到了9.该constructor()函数在Kotlin中称为次级构造函数。这个构造函数等同于我们在实例化类时调用的Java构造函数。  。

在Kotlin,没有像你可能熟悉的领域概念; 相反,它使用“属性”的概念。例如,我们已经宣布与两个可变(读写)性能var关键字:title和isbn在Book类。(如果您需要对Kotlin中的变量进行更新,请参阅本系列的第一篇文章:  变量,基本类型和数组。  在科特林,没有像你可能熟悉的领域概念; 相反,它使用“属性”的概念。例如,我们已经宣布与两个可变(读写)性能var关键字:title和isbn在Book类。(如果您需要对Kotlin中的变量进行更新,请参阅本系列的第一篇文章:  变量,基本类型和数组。 

令人惊奇的是,这些属性的getters和setter是由Kotlin编译器为我们自动生成的。 请注意,我们没有为这些属性指定任何可见性修饰符,因此默认情况下它们是公共的。换句话说,他们可以从任何地方访问。

让我们来看看Kotlin中同一个类的另一个版本:

在这段代码中,我们删除了第二个构造函数。相反,我们在称为主构造函数的类头中声明了一个构造  函数。主构造函数没有放置代码块的地方,所以我们使用init修饰符来初始化来自主构造函数的传入参数。请注意,  init 代码块在创建类实例时立即执行。 正如你所看到的,我们的代码仍然有很多样板。让我们进一步减少它: 正如你所看到的,我们的代码仍然有很多样板。让我们进一步减少它:

正如你所看到的,我们的代码仍然有很多样板。让我们进一步减少它:

我们的Book类现在只是一行代码。太棒了!请注意,在主构造函数参数列表中,我们定义了可变属性:  titleisbn 直接在主构造函数中使用var关键字。 

我们也可以将默认值添加到构造函数中的任何类属性中。

事实上,我们也可以省略  constructor关键字,但只有当它没有任何可见性修饰符(public,private,或  protected)或任何注释。 

一个非常整洁的类,我必须说!

我们现在可以像这样创建一个类实例:

访问和设置属性 

在Kotlin中,我们可以通过类对象获取属性book,然后是点分隔符  .,然后是属性名称title。这种访问属性的简洁风格称为  属性访问语法。 换句话说,我们不必调用属性getter方法来访问或调用setter来设置Kotlin中的属性,就像我们在Java中所做的那样。   换句话说,我们不必调用属性getter方法来访问或调用setter来设置Kotlin中的属性,就像我们在Java中所做的那样。 

由于该  isbn 属性是使用  var 关键字(读写)声明的,因此我们也可以使用赋值运算符更改属性值=。

我们来看另一个例子:

在这里,我们isbn使用val关键字将参数更新为不可变(只读)。我们实例化了一个类实例,book并重新分配了title属性值“Things Fall Apart Apart”。 请注意,当我们试图重新分配isbn属性值时1234,编译器抱怨道。这是因为该属性是不可变的,已经用val关键字定义。 

Java互操作性

请注意,通过var 在主构造函数中声明带有修饰符的参数  ,Kotlin编译器(幕后)帮助我们生成了属性访问器:getter和setter。如果你使用  val,它将只产生吸气剂。 

这意味着Java调用者可以通过分别调用属性的setter或getter方法来简单地获取或设置属性字段。请记住,这取决于用于定义Kotlin属性的修饰符:var或val。 

自定义Getters和Setters

在本节中,我将向您展示如何在Kotlin中为属性创建自定义访问器(getter和setter)。 如果要在将值设置为类属性之前验证或验证值,则创建自定义设置器可能很有用。并且,当您想要更改或修改应该返回的值时,自定义属性获取器可能很有用。  

创建一个自定义设置器

因为我们要为属性创建自己的自定义getter或setter,所以我们必须在类体中定义该属性,而不是构造器标题。 

这就是为什么我们将mutable(读写)  title 属性移动到类体中并给它一个默认值(否则它不会编译)。  

你可以看到我们 在属性定义set(value) 的  title右下方定义了我们自己的setter方法  - 注意你不能修改这个  set() 方法签名,因为这是编译器期望的自定义​​属性设置函数。

value 传递给该  set 方法的参数  表示由用户分配给该属性的实际值 - 如果愿意,可以更改该参数名称,但是  value 更受欢迎。我们  value 通过检查值是否为空来验证。如果为空,则停止执行并抛出异常; 否则,将该值重新分配给一个特殊  field 变量。 我们  value 通过检查值是否为空来验证。如果为空,则停止执行并抛出异常; 否则,将该值重新分配给一个特殊  field 变量。

 方法field 内部的这个特殊  变量字段  set是属性后台字段的别名 - 后台字段只是您想要修改或使用该字段数据时由属性使用的字段。不像  value,你不能重命名这个特殊的  field 变量。

创建一个自定义的Getter

为Kotlin中的一个属性创建一个自定义getter非常简单。 

在该get方法内部,我们简单地返回一个修改  field- 在我们的情况下,我们用大写字母返回了书名。 

请注意,每次我们为该title属性设置一个值时,其set方法块都会执行 -  get 每次我们检索时,方法都是一样的。 

如果您想了解Kotlin类(在类,对象或接口中定义的函数类型)的成员函数,请访问 本系列中的More Fun With Functions发布。 

更多关于构造函数

正如我前面所讨论的,我们在Kotlin中有两种类型的构造函数:小学和中学。我们可以自由地将它们结合在一个类中,如下例所示:

请注意,我们不能像在主构造函数中那样在次构造函数中声明属性。如果我们想这样做,我们必须在类体内声明它,然后在二级构造函数中初始化它。  

在上面的代码中,我们设置了new该类的属性的默认值Car(请记住,new不是Kotlin中的关键字) - 然后,如果需要,我们可以使用辅助构造函数进行更改。在Kotlin中,每个辅助构造函数都必须调用主构造函数,或者调用另一个调用主构造函数的辅助构造函数 - 我们使用this关键字来实现该构造函数  。 

还要注意,我们可以在一个类中有多个二级构造函数。 

如果一个类扩展了一个超类,那么我们可以使用super关键字(类似于Java)来调用超类的构造函数(我们将在未来的帖子中讨论Kotlin中的继承)。 

正如我前面所说,为了我们明确地将可见性修饰符包含到类中的构造函数中,我们必须包含constructor关键字 - 默认情况下,构造函数是公共的。 

在这里,我们将构造函数设为private - 这意味着用户无法直接使用其构造函数实例化对象。如果您希望用户调用另一个方法(工厂方法)间接创建对象,这可能很有用。 

2.任何和无类型

在Kotlin中,类型层次结构中最高的类型被调用Any。这相当于Java Object类型。 这意味着,在科特林所有类明确地从继承  Any的类型,包括  String,  IntDouble,等等。该Any类型包含三种方法:  equals,  toString,和hashcode。 

我们还可以Nothing在Kotlin中的类中使用总是返回异常的函数 - 换句话说,对于不能正常终止的函数。当函数返回时Nothing,我们知道它会抛出异常。在Java中不存在这种类型。  当函数返回时Nothing,我们知道它会抛出异常。在Java中不存在这种类型。 

在单元测试中测试错误处理行为时,这可以派上用场。   

3.可见性修饰符

可见性修饰符帮助我们限制我们的API对公众的可访问性。我们可以为我们的类,接口,对象,方法或属性提供不同的可见性修饰符。Kotlin为我们提供了四种可见性修饰符:

Public

这是默认设置,任何具有此修饰符的类,函数,属性,接口或对象都可以从任何地方访问。

Private

声明为顶级函数,接口或类private只能在同一个文件中访问。 

private在类,对象或接口内声明的任何函数或属性只能对同一类,对象或接口的其他成员可见。 

Protected

所述protected 改性剂可以仅被应用到性能或功能内的类,对象或接口不能被应用于顶层函数,类或接口。使用此修饰符的属性或函数只能在定义它的类和任何子类中访问。 

Internal

在具有模块(Gradle或Maven模块)的项目中,internal 只能在该模块中访问使用该模块内声明的修饰符指定的类,对象,接口或函数。 

4.智能Casting

Casting意味着采用另一种类型的对象并将其转换为另一种对象类型。例如,在Java中,我们使用instanceof运算符来确定特定的对象类型是否属于其他类型,然后再进行转换。

正如你所看到的,我们检查了shape实例是否是Circle,然后我们必须明确地将shape引用转换为Circle类型,以便我们可以调用circle类型的方法。 

关于Kotlin的另一个令人敬畏的事情是编译器在编译时的智能。现在让我们看看Kotlin的一个版本。

很简约!编译器很聪明,知道if只有当shape对象是一个实例时才会执行该块Circle,因此投影机制在我们的引擎下完成。现在我们可以轻松地调用Circle该if块内的属性或类型的函数。 这里,在最后一个条件&&的if头会被调用,只有当第一个条件是true。如果shape不是Circle,那么最后的条件将不会被评估。 

这里,if里面&&在最后一个条件被调用,只有当第一个条件是true。如果shape不是Circle,那么最后的条件将不会被评估。 

5.明确的Casting

我们可以使用as操作符(或不安全的转换操作符)将类型的引用显式转换为Kotlin中的另一种类型。 

如果显式的转换操作是非法的,请注意a ClassCastException会被抛出。为了防止在投射时抛出异常,我们可以使用安全的投射运算符as(或可为空值的投射运算符)  ?。 

as?运营商将尝试转换为预期的类型,并返回  null 如果该值不能代替投抛出异常。 请记住, 本系列中的Nullability,Loops和Conditions发布中的Nullability部分讨论了类似的机制  。阅读那里进行复习。

6.  对象

Kotlin中的对象比Java对象更类似于JavaScript对象。请注意,Kotlin中的对象不是特定类的实例!

对象与类非常相似。以下是Kotlin中对象的一些特征:

  • 他们可以拥有属性,方法和  init块。
  • 这些属性或方法可以具有可见性修饰符。
  • 他们不能有构造函数(小学或中学)。
  • 他们可以扩展其他类或实现一个接口。

现在我们来深入探讨如何创建一个对象。  

我们将object关键字放在我们想要创建的对象的名称之前。实际上,当我们使用object构造在Kotlin中创建对象时,我们正在创建单例,因为只有一个对象的实例存在。当我们讨论与Java的对象互操作性时,您将会学到更多。  当我们讨论与Java的对象互操作性时,您将会学到更多。

单例是一种软件设计模式,它保证一个类只有一个实例,并且该类提供了一个全局访问点。无论何时多个类或客户要求类,他们都会得到同一类的实例。 您可以查看我的关于Java中的单例模式的文章以了解更多信息。

您可以访问项目中任何位置的对象或单例 - 只要您导入它的包。 

如果您是Java编码人员,那么我们通常会创建单例:

正如您所看到的,使用Kotlin object构造可以简化创建单例。 

Kotlin中的对象也可以用来创建常量。通常在Java中,我们通过将其设置为公共静态final字段来在类中创建常量:

Java中的这些代码可以更简洁地转换为Kotlin,如下所示:

在这里,我们APIConstants 用baseUrl 一个包内的属性声明常量com.chike.kotlin.constants。在底层,baseUrl我们为我们创建了一个Java私有静态最终成员,并使用字符串URL进行了初始化。 

要在Kotlin的另一个包中使用此常量,只需导入包。

Java互操作性

Kotlin将对象转化为引擎盖下的最终Java类。这个类有一个私有的静态字段INSTANCE,它包含一个类的单个实例(单例)。以下代码显示了用户如何从Java调用Kotlin对象。 

在这里,调用的Java类Singleton是使用公共静态最终成员生成的INSTANCE,其中包括公共final函数myFunc()。

为了使Kotlin中的对象函数或属性成为生成的Java类的静态成员,我们使用@JvmStatic注释。以下是如何使用它:

通过应用@JvmStatic注释myFunc(),编译器将其转换为静态函数。 

现在,Java调用者可以像调用普通的静态成员调用一样调用它。请注意,使用INSTANCE静态字段来调用成员将仍然有效。

7.  Companion对象

现在我们已经了解了Kotlin中的对象,让我们深入另一种称为伴侣对象的对象。 

由于Kotlin不支持静态类,方法或属性,就像我们在Java中所使用的那样,Kotlin团队为我们提供了一个更强大的替代方法,称为伴随对象。伴侣对象基本上是一个属于类的对象 - 这个类被称为对象的伴随类。这也意味着我提到的对象的特征也适用于伴随对象。  伴侣对象基本上是一个属于类的对象 - 这个类被称为对象的伴随类。这也意味着我提到的对象的特征也适用于伴侣对象。 

创建伴随对象

类似于Java中的静态方法,伴随对象不与类实例相关联,而与类自身相关联 - 例如,工厂静态方法,它具有创建类实例的工作。 

在这里,我们构造了构造函数private- 这意味着类外的用户不能直接创建实例。在我们的伴随对象块中,我们有一个函数create(),它创建一个Person对象并将其返回。 

调用伴随对象函数

companion 对象实例化是懒惰的。换句话说,它只会在第一次需要的时候被实例化。 companion 当companion 创建一个类的实例或  companion 访问对象成员时,就会发生对象  的实例化  。 

我们来看看如何在Kotlin中调用伴随对象函数。

正如你所看到的,这就像正常情况下在Java中调用静态方法一样。换句话说,我们只是调用这个类然后调用成员。请注意,除了函数之外,我们还可以在伴随对象中包含属性。 

另请注意,companion类对其伴随对象中声明的所有属性和函数进行了无限制的访问,而伴随对象无法访问类成员。我们可以initcompanion对象内部有一个代码块 - 当创建伴随对象时立即调用这个代码块。 

执行上面的代码的结果将是: 

请记住,只能有一个类companion对象的单个实例存在。 

我们也可以自由地为我们的伴侣对象提供一个名称。 

在这里,我们给它起了一个名字Factory。我们可以在Kotlin中这样称呼它:

这种风格是冗长的,所以坚持以前的方式更受欢迎。但是,当从Java调用伴随对象函数或属性时,这可能会派上用场。

正如我前面所说,与对象一样,伴随对象也可以包含属性或函数,实现接口,甚至可以扩展一个类。 

在这里,我们PersonFactory只有一个create()功能的界面。看看我们新的修改后的  companion对象,它现在实现了这个接口(您将在后面的文章中了解Kotlin中的接口和继承)。 

Java互操作性

在引擎盖下,伴随对象的编译与Kotlin对象的编译方式类似。在我们自己的案例中,为我们生成了两个类:一个最终Person类和一个内部静态最终类Person$Companion。 

Person类包含称为最终静态成员Companion-这个静态字段是的一个目的Person$Companion 内部类。该  Person$Companion 内部类也有自己的成员,其中一人是被称为公众最终功能create()。 

请注意,我们没有给我们的伴侣对象一个名字,所以生成的静态内部类是Companion。如果我们给了它一个名字,那么生成的名字就是我们在Kotlin中给出的名字。 

这里,Kotlin中的伴随对象没有名称,所以我们使用Companion编译器为Java调用者提供的名称来调用它。

@JvmStatic应用于伴随对象成员的注释的工作方式与常规对象的工作方式类似。 

伴随对象扩展

与扩展函数如何扩展类的功能类似,我们也可以扩展伴随对象的功能。(如果您想要复习Kotlin中的扩展函数,请参阅本系列中的高级函数教程)。 

在这里,我们在伴随对象ClassA.Companion上定义了一个扩展函数extFunc()。换句话说,extfunc() 是对伴侣对象的扩展。然后,我们可以调用扩展,就好像它是伴随对象的成员函数(它不是!)。  在幕后,编译器将创建一个静态实用程序功能extFunc()。接收器对象作为该实用程序函数的参数  ClassA$Companion。 

在幕后,编译器将创建一个静态实用程序功能extFunc()。接收器对象作为该实用程序函数的参数  ClassA$Companion。 

结论

在本教程中,您了解了Kotlin中的基本类和对象。我们介绍了关于类的以下内容:

  • 类的创建
  • 构造方法
  • 属性
  • 可见性修饰符
  • 智能casting
  • 显式投射 

此外,您还了解了Kotlin中的对象和伴随对象如何轻松替换您在Java中编写的静态方法,常量和单例。但那不是全部!还有更多需要了解Kotlin的课程。在下一篇文章中,我将向您展示Kotlin面向对象编程的更多精彩功能。再见! 在下一篇文章中,我将向您展示Kotlin面向对象编程的更多精彩功能。再见!

要了解有关Kotlin语言的更多信息,我建议访问  Kotlin文档。或者在Envato Tuts +上查看我们的其他一些Android应用程序开发帖子!

Envato qr branded
关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.