提问人:Tobias Reich 提问时间:9/7/2018 更新时间:9/8/2018 访问量:2448
Kotlin:从自身/内部引用匿名对象(通过此)
Kotlin: Referencing anonymous object from itself / inside (via this)
问:
TL;DR 这些匿名对象无法通过(导致外部对象)访问自身。我怎样才能访问它?object : someClass{ }
this
更长的解释:
对于我的 Fragment,我需要一个 PreDrawListener。我在 onCreateView 中调用它。执行时,我想在之后删除侦听器。因此,Java 的执行方式会建议类似这样的事情
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
val treeObserver = layout.viewTreeObserver
treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
layout.viewTreeObserver.removeOnPreDrawListener(this)
...
}
}
问题是,当看对象时,对象不是听者,而是removeOnPreDrawListener(this)
this
myFragment$onCreateView$1@f019bf0
或者,我可以访问它直接返回对 Fragment 的引用。this@MyFragment
尽管如此,这些选项似乎都不是我的.我怎样才能从内部访问它(如果有的话)?PreDrawListener
答:
老实说,我看不出你的问题。
this
在 Inside 中,匿名者指的是类本身,但它们从来就没有名称。不能创建具有名称的匿名类。为了演示这一点,我编写了一些示例代码:
class TheClass{
fun run(){
val anon = object: Runnable {
override fun run() {}
}
println(anon::class.java.simpleName)
println(anon::class.java.name)
}
}
打印:
run$anon$1
com.package.TheClass$run$anon$1
现在,这很好,但它看起来仍然不像你的。但是你会看到它与包含的类、方法、变量匹配,最后是表示它是一个匿名内部类的美元符号。这适用于第二个,即完整的。第一个只是打印短名称,即方法、var 名称,以及显示其匿名函数的美元符号。
如果您对为什么会出现带有数字的美元符号感兴趣,请参阅此处。T
让我们扩展它并抛弃变量。显然,这是可怕的代码(而且远非内存效率,但它是一个演示,所以没关系):
class TheClass {
fun run(){
println(object: Runnable {
override fun run() { }
})
}
}
这将打印并匹配您的图案:
com.package.TheClass$run$anon$1
你已经看到了这种模式;现在你可以开始“解码”你得到的哈希值了:
myFragment // inside myFragment
$onCreateView // Inside a function
$1 // There is an anonymous class with a specific identifier
@f019bf0 // This is standard everywhere; just look up Object.toString()
我刚才试图证明的是:确实是指您创建的匿名函数。匿名函数是匿名的。他们没有名字。它们用作标识符。因此,如果您有以下代码:this
$number
treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
layout.viewTreeObserver.removeOnPreDrawListener(this)
...
}
}
this
将引用侦听器,即使打印类可能会打印看起来令人困惑的内容。如果有什么东西坏了,那不是因为没有提到听众(因为它确实如此)this
此外,您的代码编译良好。那里也没有类型不匹配。如果它引用了不同的对象,则如果传递给需要 .this
OnPreDrawListener
在 Java 中使用相同的代码会得到不同的结果。这是因为 Kotlin 将匿名函数编译为 ,而 Java 将其编译为 .如果它位于嵌套类中,它将在 Kotlin 和 Java 中显示。Class$function$number
Class$number
Outer$Inner$function$number
Outer$Inner$number
编译器中的差异导致名称不同;Java 排除了该函数,而 Kotlin 则包含该函数。它位于文件名中,因此,如果您构建项目并在文件资源管理器中查看您拥有的任何操作系统的文件名(请勿在 IntelliJ.它将为您反编译文件。请记住,您只是在寻找名称,IntelliJ通过将.class文件合并为一个文件以匹配原始来源来搞砸该名称).class
就像最终的元一样,我确实打印了类而不是打印对象。接口没有被覆盖的 toString 方法,这意味着它默认为 Object 上的方法,它返回 getClass().getName() + “@” + Integer.toHexString(hashCode()); (
原始代码可以在这里找到)。println(this
) 与 println(this.toString())
相同,后者调用 Object 中的 toString 方法,后者打印类名。println(this)
与打印对象或打印类相同
评论
myFragment$onCreateView$1@f019bf0
是侦听器的继承实现。您应该能够覆盖它(除了 )并看到它的变化。toString()
onPreDraw