【问题标题】:Get companion class in companion object在伴生对象中获取伴生类
【发布时间】:2017-07-06 11:08:25
【问题描述】:

有没有办法在不知道它的名字的情况下在伴生对象中获取伴生类的javaClass

我想我可以通过这样做来获得它:

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

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

我希望有更直接的东西,比如this::class.companionClass

【问题讨论】:

  • 为什么不在javaClass那里?
  • val clazz = TestClass::class.java 怎么样?
  • 啊,我的错,澄清了问题 - 我想在编译时不知道名称的情况下获取该类。

标签: kotlin


【解决方案1】:

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

TestClass::class.companionObject

这是一个例子:

class TestClass {

    companion object {
        fun sayHello() = "Hello world"
    }
}

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

class TestClass {

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

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

import kotlin.reflect.KClass

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

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

class TestClass {

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

【讨论】:

    【解决方案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 {
             }
         }
    }
    

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

    public final class TestClass {
        public static final Companion companion = ...
    }
    

    因此,您可以像刚才一样通过切断类名的.Companion 部分来执行此操作,也可以使用TestClass::class.java 硬引用它(在我看来没有问题,最好的解决方案)

    【讨论】:

    • 真可惜。此外,将问题更新为更清楚:我想在运行时获取实际的类,即使它是子类。
    【解决方案3】:

    如果需要打印类名,可以加上simpleName,如

    this::class.java.declaringClass.simpleName
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-12
      • 2022-11-29
      • 1970-01-01
      • 2014-04-17
      • 1970-01-01
      相关资源
      最近更新 更多