如何在kotlin中使用reflect访问静态字段?

如何在kotlin中使用reflect访问静态字段?,kotlin,Kotlin,我有一个java抽象类: abstract class AbsApiTestCase<T> { T mApi; @Before public void setUp() throws Exception { mApi = instanceApi((Class<T>) ( (ParameterizedType) getClass().getGenericSuperclass())

我有一个java抽象类:

abstract class AbsApiTestCase<T> {
    T mApi;

    @Before
    public void setUp() throws Exception {
        mApi = instanceApi((Class<T>) (
                  (ParameterizedType) getClass().getGenericSuperclass())
                     .getActualTypeArguments()[0]);
    }

    static <T> T instanceApi(Class<T> clazz) throws Exception {
        return new Retrofit.Builder()
            .baseUrl(clazz.getField("BASE_URL").get(null).toString())
            .addConverterFactory(GsonConverterFactory.create(
                    new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create()))
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .client(getClient())
            .build().create(clazz);

    }
    // some code
}
它可以这样使用:

public interface GithubApi {
    String BASE_URL = "https://api.github.com/";
    // some code
}
public class GithubApiTest extends AbsApiTestCase<GithubApi> {
    // some code
}
interface GithubApi {
    companion object {
        val BASE_URL = "https://api.github.com/"
    }
    // some code
}
BASE\u URL
不能像上面那样访问。我发现有一个
@JvmField
注释,但是Android studio说
JvmField不能应用于接口的伴随对象中定义的属性


有办法访问此“静态字段”吗?

JvmStatic
注释将使属性的支持字段成为静态字段。也就是说,如果注释应用于伴生对象中的属性,则将在封闭类中创建一个新的静态字段


请注意,Kotlin实际上没有静态的概念,并且此注释仅用于跨JVM语言的可访问性。

BASE\u URL
设为编译时常量如何

interface GithubApi {
    companion object {
        const val BASE_URL = "https://api.github.com/"
    }
}
在字节码级别
BASE\u URL
GithubApi
接口的静态字段

public interface GithubApi {
  public static final GithubApi$Companion Companion;

  public static final java.lang.String BASE_URL;

  static {};
    Code:
       0: new           #26                 // class GithubApi$Companion
       3: dup
       4: aconst_null
       5: invokespecial #30                 // Method GithubApi$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
       8: putstatic     #32                 // Field Companion:LGithubApi$Companion;
      11: return
}
public class AllUrls {
    public static final String GITHUB_URL = "https://api.github.com/";
}
公共接口GithubApi{ 公共静态最终GithubApi$Companion Companion; public static final java.lang.String BASE_URL; 静态{}; 代码: 0:new#26//class GithubApi$Companion 3:dup 4:aconst_null 5:invokespecial#30//方法GithubApi$Companion.“:(Lkotlin/jvm/internal/DefaultConstructorMarker;)V 8:putstatic#32//字段同伴:LGithubApi$Companion; 11:返回 }
我看到了四个基本选项:

1) 将属性提取到对象中(是否伴随):

2) 创建包级属性:

package myProgram

val BASE_URL = "https://api.github.com/"
3) 如果需要继承,请使用类而不是接口(不知道继承的目的是什么,待定):

4) 用接口中的方法替换字段(可以重写):


根本不建议在接口中放置常量。它引入了太多的复杂性,而没有真正的价值增益

尝试将保持常量的类与实现接口的实际类分离

public interface GithubApi {
  public static final GithubApi$Companion Companion;

  public static final java.lang.String BASE_URL;

  static {};
    Code:
       0: new           #26                 // class GithubApi$Companion
       3: dup
       4: aconst_null
       5: invokespecial #30                 // Method GithubApi$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
       8: putstatic     #32                 // Field Companion:LGithubApi$Companion;
      11: return
}
public class AllUrls {
    public static final String GITHUB_URL = "https://api.github.com/";
}
这将成为

object AllUrls {
    val GITHUB_URL = "https://api.github.com/"
}
以及如何使用它

 static <T> T instanceApi(Class<T> clazz) throws Exception {
    return new Retrofit.Builder()
        .baseUrl(AllUrls.INSTANCE.getGITHUB_URL())
        .addConverterFactory(GsonConverterFactory.create(
                new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create()))
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(getClient())
        .build().create(clazz);

}
静态T instanceApi(类clazz)引发异常{
返回新的改装.Builder()
.baseUrl(AllUrls.INSTANCE.getGITHUB_URL())
.addConverterFactory(GsonConverterFactory.create(
新的GsonBuilder().setDateFormat(“yyyy-MM-dd HH:MM:ss”).create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getClient())
.build().create(clazz);
}

您计划如何使用
GithubApi
?你需要从Java访问吗?@voddan不,我只需要一个url值来创建实例,但我在
KClass中找不到它。members
我也尝试了
@JvmStatic
,IDE说
只有类的命名对象和伴生对象中的函数可以用“@JvmStatic”注释。
中使用了Api接口,它必须是一个接口。如果我用一个函数替换它,要访问它,我需要一个实例,要创建一个实例,我需要url值,这看起来像是一个循环。我的观点是,您不需要将静态信息放入接口中。URL可能存储在接口附近的任何位置(选项1和2)。没错,我可以将其放在映射中,并使用类名访问它(GithubApi不是唯一的这样的接口,它甚至不是我代码中的真实接口,它只是一个示例),但我发布的这些代码只是用于测试用例,代码更少,性能也不那么重要,我确实在真实代码中使用了
reformation.Builder().baseUrl(GithubApi.BASE\u URL)
。那么,也许一个伴生对象就是使用
AllUrls.INSTANCE.getGITHUB\u URL()
的方法,现在这个方法只能用于GithubApi,这样我们甚至不需要
clazz
。我不认为在接口中放入常量是错误的,在android.os.PARCELABLE中有一个整数常量
PARCELABLE\u WRITE\u RETURN\u VALUE
 static <T> T instanceApi(Class<T> clazz) throws Exception {
    return new Retrofit.Builder()
        .baseUrl(AllUrls.INSTANCE.getGITHUB_URL())
        .addConverterFactory(GsonConverterFactory.create(
                new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create()))
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .client(getClient())
        .build().create(clazz);

}