在 Kotlin 中处理字段的正确方法是什么?
What is the correct way to deal with fields in Kotlin?
我应该如何正确处理从 Java class 字段到 Kotlin 的迁移?
阅读 Kotlin 的文档后发现,他们的 classes 不能在其中定义字段。作为我的反叛者,实际上试图将我现有的 Java 代码转换为它的 Kotlin 对应代码(使用 Android Studio 的 Java 到 Kotlin 转换器功能)也将 "fields" 标记为.
这是我的 Java class:
public final class PaperDay implements Day {
private Date date;
private Weather weather;
PaperDay() {
// Obligatory empty ctor for Paper.
}
PaperDay(Date date) {
this.date = truncateTimeFromDate(date);
this.weather = Weather.SUNNY; // Default to SUNNY, 'cos sunny is good!
}
PaperDay(Date date, Weather weather) {
this.date = truncateTimeFromDate(date);
this.weather = weather;
}
private Date truncateTimeFromDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
...
..这就是转换成 .kt 的样子:
我怎样才能用 Kotlin 的方式做到这一点?
我假设你想要这样的东西:
class PaperDay (private var date: Date,
private var weather: Weather = Weather.SUNNY) : Day {
init {
this.date = truncate(date)
}
private fun truncateTimeFromDate(date1: Date): Date {
return date1
}
}
您应该尽可能使用可选参数 (var weather: Weather = Weather.SUNNY
),因为它会大大提高可读性。
为了避免(有点难看)init
块,您还可以仅将两个属性之一作为构造函数参数传递(感谢 Jayson Minard),并在其中计算另一个 属性使用 "normal" 参数声明:
class PaperDay (dateWithTime: Date,
private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
...
}
请注意,这也使用 val
而不是 var
,因为不变性通常是更好的选择。
如果你也需要有空的构造函数,你可以添加这个(虽然我不认为这是一个好的做法并且它是 "bad" 的一个指标
设计:
constructor() : this(Date())
或者,在构造函数中为 所有 参数添加默认值也会隐式创建一个空构造函数。
如果您真的想要空性,请使用 ?
定义您的属性。例如:
class PaperDay (private var date: Date?, private var weather: Weather? = Weather.SUNNY)
然后您还可以将另一个构造函数更改为 constructor() : this(null)
此外,恕我直言,将 truncate...
方法添加为日期 class 的 extension function 而不是将其放在此 class 中也是一个好主意:
fun Date.truncateTimeFromDate() {
Calendar calendar = Calendar.getInstance()
calendar.setTime(this)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
...
}
类似于@Lovis 但避免使用 var
应该是 "last resort":
class PaperDay (dateWithTime: Date = Date(), private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
...
}
}
在此版本中,构造函数有一个 参数 不是 class 属性,另一个是 属性。稍后在 class 正文中,声明 属性 并将其设置为截断日期。
如果每个构造函数参数都有一个默认值,Kotlin 将自动创建一个使用这些默认值的默认构造函数。无需单独添加。
如果您的框架必须使用默认构造函数实例化,然后在事后设置值,您将需要执行类似以下操作并返回使用 var
:
class PaperDay (dateWithTime: Date = Date(), private var weather: Weather = Weather.SUNNY): Day {
private var date: Date = truncateTimeFromDate(dateWithTime)
set(value) { field = truncateTimeFromDate(value) }
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
return dateWithTime
}
}
现在我们通过自定义 setter.
确保我们永远不会将无效日期存储在 属性 中
如果您希望 Java 提供的构造函数的所有变体具有互操作性,您可以在构造函数上使用 @JvmOverloads
annotation 来生成使用默认参数值的其他排列。
正如@Lovis 指出的那样,将 truncateTimeFromDate
移动到 Date
class 上的扩展函数。它可以在文件、模块、class 的本地,在所有这些情况下,它的读起来会更好。
我应该如何正确处理从 Java class 字段到 Kotlin 的迁移?
阅读 Kotlin 的文档后发现,他们的 classes 不能在其中定义字段。作为我的反叛者,实际上试图将我现有的 Java 代码转换为它的 Kotlin 对应代码(使用 Android Studio 的 Java 到 Kotlin 转换器功能)也将 "fields" 标记为
这是我的 Java class:
public final class PaperDay implements Day {
private Date date;
private Weather weather;
PaperDay() {
// Obligatory empty ctor for Paper.
}
PaperDay(Date date) {
this.date = truncateTimeFromDate(date);
this.weather = Weather.SUNNY; // Default to SUNNY, 'cos sunny is good!
}
PaperDay(Date date, Weather weather) {
this.date = truncateTimeFromDate(date);
this.weather = weather;
}
private Date truncateTimeFromDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
...
..这就是转换成 .kt 的样子:
我怎样才能用 Kotlin 的方式做到这一点?
我假设你想要这样的东西:
class PaperDay (private var date: Date,
private var weather: Weather = Weather.SUNNY) : Day {
init {
this.date = truncate(date)
}
private fun truncateTimeFromDate(date1: Date): Date {
return date1
}
}
您应该尽可能使用可选参数 (var weather: Weather = Weather.SUNNY
),因为它会大大提高可读性。
为了避免(有点难看)init
块,您还可以仅将两个属性之一作为构造函数参数传递(感谢 Jayson Minard),并在其中计算另一个 属性使用 "normal" 参数声明:
class PaperDay (dateWithTime: Date,
private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
...
}
请注意,这也使用 val
而不是 var
,因为不变性通常是更好的选择。
如果你也需要有空的构造函数,你可以添加这个(虽然我不认为这是一个好的做法并且它是 "bad" 的一个指标 设计:
constructor() : this(Date())
或者,在构造函数中为 所有 参数添加默认值也会隐式创建一个空构造函数。
如果您真的想要空性,请使用 ?
定义您的属性。例如:
class PaperDay (private var date: Date?, private var weather: Weather? = Weather.SUNNY)
然后您还可以将另一个构造函数更改为 constructor() : this(null)
此外,恕我直言,将 truncate...
方法添加为日期 class 的 extension function 而不是将其放在此 class 中也是一个好主意:
fun Date.truncateTimeFromDate() {
Calendar calendar = Calendar.getInstance()
calendar.setTime(this)
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
...
}
类似于@Lovis 但避免使用 var
应该是 "last resort":
class PaperDay (dateWithTime: Date = Date(), private val weather: Weather = Weather.SUNNY): Day {
private val date: Date = truncateTimeFromDate(dateWithTime)
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
...
}
}
在此版本中,构造函数有一个 参数 不是 class 属性,另一个是 属性。稍后在 class 正文中,声明 属性 并将其设置为截断日期。
如果每个构造函数参数都有一个默认值,Kotlin 将自动创建一个使用这些默认值的默认构造函数。无需单独添加。
如果您的框架必须使用默认构造函数实例化,然后在事后设置值,您将需要执行类似以下操作并返回使用 var
:
class PaperDay (dateWithTime: Date = Date(), private var weather: Weather = Weather.SUNNY): Day {
private var date: Date = truncateTimeFromDate(dateWithTime)
set(value) { field = truncateTimeFromDate(value) }
private fun truncateTimeFromDate(dateWithTime : Date) : Date {
return dateWithTime
}
}
现在我们通过自定义 setter.
确保我们永远不会将无效日期存储在 属性 中如果您希望 Java 提供的构造函数的所有变体具有互操作性,您可以在构造函数上使用 @JvmOverloads
annotation 来生成使用默认参数值的其他排列。
正如@Lovis 指出的那样,将 truncateTimeFromDate
移动到 Date
class 上的扩展函数。它可以在文件、模块、class 的本地,在所有这些情况下,它的读起来会更好。