7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Kotlin

Kotlin从零开始:课程和对象

Scroll to top
Read Time: 5 mins
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应用程序开发帖子!

关注我们的公众号
Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
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.