免责声明:这是用Kotlin编码的,不是一些简单的初学者级代码。请不要标记它,因为您认为我是一个不知道Null Pointer Exception是什么的菜鸟。比这复杂得多。我之前上传了这个问题,建议您查找什么是Null Pointer Exceptions,然后将我的问题标记为与有关Null Pointer Exceptions的问题重复,然后立即关闭。如果您来自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)
}
这些是我用来使菜单和MenuItems的创建更加容易的构建器模式,但是使用MenuItem(// parameters)键入应该具有相同的效果(并产生相同的错误)。
possible ways to get NullPointerException in Kotlin之一是:
这就是您的示例中正在发生的事情。您最终将在init
类的Item
块中访问component
属性,该属性尚未初始化,因为派生的Menu
类构造函数尚未完成。这种情况在https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order中进行了描述。
如果在基类构建过程中需要component
值,则可以将其与其他参数一起传递给基类构造函数。