购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

3.1 一个简单的值类型

让我们深入到代码库中,将现有的一些Java代码转换为Kotlin,从EmailAddress开始。这是一个值类型,它包含了一个电子邮件地址的两个部分:

这个类很简单,它只封装了两个字符串,并且没有提供对本身的操作。即便如此,它还是有很多代码:

❶ 值是不可变的,因此该类将其字段声明为final。

❷ 有一个静态工厂方法可以将字符串解析为EmailAddress,它调用了主构造函数。

❸ 字段在构造函数中初始化。

❹ 其属性访问器方法遵循JavaBean命名约定。

❺ 该类实现了equals和hashCode方法以确保所有字段相等的两个EmailAddress值在进行比较时是相等的。

❻ toString返回(电子邮件地址)标准形式。

代码的作者们来自Java学院,他们假设我们传递、存储或返回的所有内容都不为空,除非有明确说明。由于它缺少@Nullable注解或参数的空检查(第4章中将讨论可空性),这种约定可能不会在代码中明确体现。在这个例子中你可以看到,表达一个由两个其他值组成的值对象所需的样板代码量。令人高兴的是,IDE为我们生成了equals和hashCode方法。但是如果我们更改类的字段,一定要删除并重新生成这些方法以避免出现混淆错误。

关于Java就说这么多,我们是为Kotlin而来的。那么,如何将Java转换为Kotlin呢?幸运的是,IntelliJ提供了一个名为“Convert Java File to Kotlin File”的操作,当我们调用它时,IntelliJ会在必要时提示“是否更改其他文件以保持一致”,由于转换可能会修改整个项目中的文件,所以最好选择“是”。

确保在将Java代码转换为Kotlin之前没有未提交的更改,以便你可以轻松查看转换对代码库其他部分的影响,并在转换发生意外时进行回退。

在当前这个例子中,IntelliJ不必更改任何其他文件。它已经用同一目录中的 EmailAdd-ress.kt 替换了我们的 EmailAddress.java 文件,但是:

Kotlin类明显更加简洁,因为它在主构造函数中声明了它的属性:通过类名后面的参数。标记为val的参数被视为属性,因此Kotlin主构造函数的定义等同于下面所有这些Java代码:

主构造函数语法很方便,但它确实会干扰类的可读性。遵循标准编码约定的Java类总是以相同的顺序定义其元素:类名、超类、接口,然后是类主体、字段、构造函数和方法。这样可以轻松地浏览类并快速找到你感兴趣的特征。

找到Kotlin类中的各个部分并不是那么容易。Kotlin类定义有一个header部分,其中包含类名、主构造函数(可以包含参数和/或属性定义)、超类(也可能是对超类构造函数的调用)和接口。然后,在类的body中有更多的属性、构造函数、方法和伴生对象。

来自Java世界的我们(Nat和Duncan)一开始肯定会发现Kotlin类更难阅读,尽管最终我们习惯了,但有时仍然发现很难将Kotlin类格式化以获得最佳的可读性,特别是当header部分包含大量代码时。一种简单的解决方法是将构造函数参数列表分行放置,我们可以将光标放在参数列表中,使用Alt-Enter和“Put parameters on separate lines”来完成该操作。在header后面添加空行有时也会有所帮助:

Kotlin一处明显不如Java简洁的地方是它使用伴生对象来托管静态状态和方法,例如本例中的parse()方法。在Kotlin中,我们通常更喜欢使用顶级状态和函数,而不是这些类范围的成员。第8章讨论了两者的利弊。

目前有一些使用静态方法的Java代码,例如下面的测试类:

伴生对象与@JVMStatic注解结合使用,意味着当我们将Java类转换为Kotlin时,这部分代码不必做出改变,因此暂时让parse保持原样,我们将在第8章中讨论如何重构为顶级函数。

如果你是Kotlin新手,可能想知道getLocalPart()和getDomain()两个访问器方法发生了什么。声明domain属性会导致编译器生成一个私有domain字段和一个getDomain()方法,以便Java代码仍然可以调用它。这是一段用来支持一个营销计划的简单代码:

可以看到,Java代码正在通过getDomain()方法访问domain属性。反之亦然,当Java类具有显式的getDomain()方法时,Kotlin代码可以通过address.domain来调用它。我们将在第11章中更详细地讨论属性。

到目前为止,将Java类转换为Kotlin已经为我们节省了14行代码,但我们的工作还没有完成。像这样的值类型非常有用,但要正确地完成这些转换并保持其正常工作却非常乏味,以至于Kotlin提供了语言级别上的支持。如果我们用data修饰符标记类,则编译器会为我们生成所有尚未定义的equals、hashCode和toString方法。这使得EmailAddress类的代码简化为:

❶ 我们不想使用生成的toString()方法,所以定义了自己想要的toString()。

坦率地说,parse方法仍然令人恼火,它占用了这项工作的过多空间。我们将在第9章中最终解决这个问题,不过现在我们已经完成了将EmailAddress这个Java类转换为Kotlin的工作。 q6PG+s+I+wms76NJgfWCa2Tn3jMa50TLr2IylF4VJ6DBRPBc4FfevpWg4cvSKoIE

点击中间区域
呼出菜单
上一章
目录
下一章
×