TL; DR
这些object : someClass{ }
匿名对象无法通过this
访问自身(这导致外部对象)。 如何访问它?
更长的解释:
对于我的片段,我需要一个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
或者,我可以访问this@MyFragment
,它直接返回对Fragment的引用。
不过,这些选项似乎都不是我的PreDrawListener
。 如何从内部访问它(如果有的话)?
答案 0 :(得分:3)
老实说我看不到你的问题。
匿名内部的 this
指的是类本身,但它们从来没有名称。您不能使用名称创建匿名类。为了演示这一点,我编写了一些示例代码:
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
现在,这一切都很好,但是仍然看起来不像你的。但是您会看到它与包含的类,方法,变量以及最后一个表示它是匿名内部类的美元符号匹配。这适用于第二个,即完整的一个。第一个只是打印短名称,即方法,变量名,以及再次显示其匿名功能的美元符号。
如果您对为什么带有数字的美元符号感兴趣,请参见this。 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将匿名函数编译为Class$function$number
,而Java将匿名函数编译为Class$number
。如果在嵌套类中,它将在Kotlin中显示为Outer$Inner$function$number
,在Java中显示为Outer$Inner$number
。
编译器的不同导致名称不同; Java不包括该功能,而Kotlin则包括该功能。该文件位于.class
文件名中,因此,如果您构建项目并在文件浏览器中查看文件名称,以了解所拥有的操作系统( 请勿在IntelliJ 中查找>。它将为您反编译文件。请记住,您只是在寻找名称,IntelliJ通过将.class文件合并为一个文件来匹配原始源而弄乱了名称。
就像最终的meta一样,我确实打印类而不是打印对象。接口没有重写的toString方法,这意味着它默认为Object上的那个,该方法返回getClass().getName() + "@" + Integer.toHexString(hashCode());
(可以在here中找到原始代码)。 println(this)
与println(this.toString())
相同,后者在Object中调用toString方法,该方法打印类名。 println(this)
与打印对象或打印类相同。