Kotlin:从自身/内部引用匿名对象(通过 this)

Tob*_*ich 5 android this anonymous-class kotlin

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)
        ...
     }
  }
Run Code Online (Sandbox Code Playgroud)

问题是,当观察对象时,removeOnPreDrawListener(this)对象this不是听众,而是myFragment$onCreateView$1@f019bf0

或者,我可以访问this@MyFragment它直接返回对片段的引用。

不过,这些选项似乎都不适合我PreDrawListener我如何从内部访问它(如果有的话)?

Zoe*_*Zoe 3

老实说,我没有看到你的问题。

thisinside 匿名指的是类本身,但它们从来没有名称。您无法创建具有名称的匿名类。为了演示这一点,我编写了一些示例代码:

class TheClass{
    fun run(){
        val anon = object: Runnable {
            override fun run() {}
        }
        println(anon::class.java.simpleName)
        println(anon::class.java.name)
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个打印:

run$anon$1
com.package.TheClass$run$anon$1
Run Code Online (Sandbox Code Playgroud)

现在,这一切都很好,但它看起来仍然不像你的。但您会看到它与包含的类、方法、变量相匹配,最后是美元符号,表示它是一个匿名内部类。这适用于第二个,这是完整的。第一个只打印短名称,即方法、var 名称,以及显示其匿名函数的美元符号。

如果您对为什么会出现带有数字的美元符号感兴趣,请参阅。时间

让我们扩展它并放弃变量。显然,这是可怕的代码(并且远非内存效率高,但它是一个演示,所以没关系):

class TheClass {
    fun run(){
        println(object: Runnable {
            override fun run() { }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

这将打印并匹配您的模式:

com.package.TheClass$run$anon$1
Run Code Online (Sandbox Code Playgroud)

你已经看到了这个模式;现在你可以开始“解码”你得到的哈希值:

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()
Run Code Online (Sandbox Code Playgroud)

我只是想证明的是:this确实引用了您创建的匿名函数。匿名函数就是匿名的。他们没有名字。他们用作$number标识符。所以如果你有这个代码:

treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
       layout.viewTreeObserver.removeOnPreDrawListener(this)
       ...
    }
 }
Run Code Online (Sandbox Code Playgroud)

this将引用侦听器,即使打印类可能会打印看起来令人困惑的内容。如果有什么东西被破坏了,那不是因为this没有引用听众(因为它确实引用了)

另外,你的代码编译得很好。那里也不存在类型不匹配的情况。如果它引用了不同的对象,那么如果您传递this给需要OnPreDrawListener.


在 Java 中使用相同的代码会得到不同的结果。这是因为 Kotlin 将匿名函数编译为Class$function$number,而 Java 将其编译为Class$number. 如果它位于嵌套类中,它将像Outer$Inner$function$number在 Kotlin 和Outer$Inner$numberJava 中一样显示。

这是编译器的不同导致了不同的名称;Java 排除了该函数,而 Kotlin 则包含该函数。它位于.class文件名中,因此如果您构建项目并在文件资源管理器中查看您拥有的任何操作系统的文件名(不要查看 IntelliJ。它会为您反编译文件。记住,您只是在寻找名称,IntelliJ 通过将 .class 文件合并为一个文件以匹配原始源来弄乱该名称)


就像最终元一样,我打印类而不是打印对象。接口没有重写的 toString 方法,这意味着它默认为 Object 上的方法,该方法返回(原始代码可以在此处getClass().getName() + "@" + Integer.toHexString(hashCode());找到)。与 相同,调用 Object 中的 toString 方法,打印类名。与打印对象或打印类相同println(this)println(this.toString())println(this)