【发布时间】:2020-08-26 12:54:30
【问题描述】:
免责声明: 这是用 Kotlin 编码的,它不是一些简单的初学者级别的代码。请不要标记它,因为您认为我是一个不知道空指针异常是什么的菜鸟。它比这复杂得多。我之前上传了这个问题,并被建议查找什么是空指针异常,然后将我的问题标记为与空指针异常是什么的问题重复,然后立即关闭。如果您来自 Java,Kotlin 甚至不允许您在不分配对象的情况下创建对象(没有指定它们可以为空并提供空安全检查每次使用它们时)。我的问题没那么简单,请先看一下。我的问题在我读完整本书之前就已经结束了,所以至少在你认为我只是愚蠢之前做到这一点。
信息:
这是一个 Swing 应用程序
我在 Kotlin 中编写代码
我正在尝试为 Swing 的边界创建一个类系统(搜索“干净代码边界”以获取更多信息)。本质上,我有两个类都继承自我创建的 Item 类。
abstract class Item(var text: String = "", var icon: Icon? = null, var items: ArrayList<Item> = ArrayList()) {
abstract var component: JComponent
init {
applyProperties()
applyItems()
}
fun applyProperties() {
when (component) {
is JMenu -> {
(component as JMenu).text = text
(component as JMenu).icon = icon
}
is JMenuItem -> {
(component as JMenuItem).text = text
(component as JMenuItem).icon = icon
}
}
}
fun applyItems() {
for (item in items) {
apply(item)
}
}
private fun apply(item: Item) {
component.add(item.component)
}
companion object {
fun ArrayList<Item>.addItems(vararg items: Item) {
this.addAll(items)
}
}
}
另外两个类除了覆盖组件变量什么都不做,然后applyProperties()中的switch语句可以使用组件变量类型来知道要设置哪些变量。就像现在一样,两个类需要设置的变量是相同的,但我使用的是多态性,所以以后可以添加更多具有不同功能的类。这是其中之一,只是为了向您展示它们几乎不可能是原因。
class Menu(text: String = "", icon: Icon? = null, items: ArrayList<Item> = ArrayList()): Item(text, icon, items) {
override var component: JComponent = JMenu()
}
这是我运行的引发空指针异常的代码。
var menu: JMenu = MenuBuilder().set { menu ->
menu.text = "Save"
menu.items.addItems(
MenuItemBuilder().set { menuItem ->
menuItem.text = "Save"
}.build(),
MenuItemBuilder().set { menuItem ->
menuItem.text = "Save As"
}.build()
)
}.build()
apply() 上调用的 applyItems() 方法调用 add(),它接收一个 JComponent 作为输入,然后抛出异常。但是,我输入的组件总是在运行 add() 之前设置。它是一个抽象变量,总是在创建类 Item 的实例时设置。此外,如果我忘记设置它,它甚至不应该让我运行。我在 Kotlin 中对此进行编码,它具有极高的 null 安全性。除非我自己抛出一个空指针异常,否则我不应该得到空指针异常。它甚至不是一个可以为空的变量,那为什么 add() 会抛出异常呢?
如果您想检查任何其他用于执行此操作的类,以查看它们是否可能导致空指针异常,我将它们全部放在下面。
class MenuBuilder {
var text: String = ""
var icon: Icon? = null
var items: ArrayList<Item> = ArrayList()
fun set(builderFunction: (MenuBuilder) -> Unit): MenuBuilder {
builderFunction(this)
return this
}
fun build() = Menu(text, icon, items)
}
class MenuItemBuilder {
var text: String = ""
var icon: Icon? = null
var items: ArrayList<Item> = ArrayList()
fun set(builderFunction: (MenuItemBuilder) -> Unit): MenuItemBuilder {
builderFunction(this)
return this
}
fun build() = MenuItem(text, icon, items)
}
这些是我用来使创建菜单和菜单项更容易的构建器模式,但是使用键入 MenuItem(//parameters) 应该具有相同的效果(并产生相同的错误)。
【问题讨论】:
-
问题看起来是合法的,但是你可以将它作为参数而不是抽象的,并在创建子类时将参数传递给超类构造函数。这可能是因为先调用了super,然后在子类中初始化了变量。
标签: swing kotlin nullpointerexception jcomponent