在同伴对象中获取同伴类

shu*_*fan 5 kotlin

有没有一种方法可以在javaClass不知道同伴对象名称的情况下将其添加到同伴对象中?

我想我可以通过执行以下操作来实现:

open class TestClass {
    companion object {
        init {
            val clazz = Class.forName(this::class.java.canonicalName.removeSuffix(".Companion"))
        }
    }    
}
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于class InheritingClass : TestClass()。它仍然会给我TestClass,而不是InheritingClass。

我希望有更简单的东西this::class.companionClass

Dav*_*zzo 10

获取给定类的伴生对象的类将如下所示:

TestClass::class.companionObject
Run Code Online (Sandbox Code Playgroud)

下面是一个例子:

class TestClass {

    companion object {
        fun sayHello() = "Hello world"
    }
}
Run Code Online (Sandbox Code Playgroud)

如果要获取包含同伴的类,因为后者始终是前者的内部类,

class TestClass {

    companion object {
        fun whichIsMyParentClass() = this::class.java.declaringClass // It'll return TestClass
    }
}
Run Code Online (Sandbox Code Playgroud)

为了进一步简化,您还需要创建一个扩展属性:

import kotlin.reflect.KClass

val <T : Any> KClass<T>.companionClass get() =
    if (isCompanion)
        this.java.declaringClass
    else
        null
Run Code Online (Sandbox Code Playgroud)

所以,每当你想要获取伴生对象的父类时,

class TestClass {

    companion object {
        fun whichIsMyParentClass() = this::class.companionClass // It'll return TestClass
    }
}
Run Code Online (Sandbox Code Playgroud)


gue*_*ter 2

正如您在此字节码中看到的那样,伴随类本身没有对实际类的引用

public final class TestClass$Companion {

     private TestClass$Companion() { // <init> //()V
         <localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>

         L1 {
             aload0 // reference to self
             invokespecial java/lang/Object <init>(()V);
             return
         }
         L2 {
         }
     }

     public TestClass$Companion(kotlin.jvm.internal.DefaultConstructorMarker arg0) { // <init> //(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
         <localVar:index=0 , name=this , desc=LTestClass$Companion;, sig=null, start=L1, end=L2>
         <localVar:index=1 , name=$constructor_marker , desc=Lkotlin/jvm/internal/DefaultConstructorMarker;, sig=null, start=L1, end=L2>

         L1 {
             aload0 // reference to self
             invokespecial TestClass$Companion <init>(()V);
             return
         }
         L2 {
         }
     }
}
Run Code Online (Sandbox Code Playgroud)

引用只是相反(参见反编译的 kotlin 类)

public final class TestClass {
    public static final Companion companion = ...
}
Run Code Online (Sandbox Code Playgroud)

因此,您可以像刚才那样通过切断.Companion类名的部分来完成它,或者通过硬引用它TestClass::class.java(在我看来没有问题,也是最好的解决方案)