如何访问反映在kotlin的静态字段?
我在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 }
而api看起来像这样:
public interface GithubApi { String BASE_URL = "https://api.github.com/"; // some code }
它可以像这样使用:
public class GithubApiTest extends AbsApiTestCase<GithubApi> { // some code }
但是,当我将我的代码转换为kotlin时,静态字段BASE_URL
如下所示:
interface GithubApi { companion object { val BASE_URL = "https://api.github.com/" } // some code }
BASE_URL
不能像上面那样访问。 我发现有一个@JvmField
批注,但Android工作室说JvmField cannot be applied to a property defined in companion object of interface
。
有没有办法访问这个“静态字段”?
如何使BASE_URL
编译时常量?
interface GithubApi { companion object { const val BASE_URL = "https://api.github.com/" } }
在字节码级别, BASE_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 }
我看到了四个基本的选择:
1)将属性提取到对象(伴随或不伴随)中:
object GithubApiUrls { val BASE_URL = "https://api.github.com/" }
2)制作一个包级别的属性:
package myProgram val BASE_URL = "https://api.github.com/"
3)如果需要继承(不知道TBH是什么),可以使用类而不是接口:
open class GithubApi { val BASE_URL = "https://api.github.com/" }
4)用接口中的方法替换该字段(可以被覆盖):
interface GithubApi { fun BaseUrl() = "https://api.github.com/" }
根本不建议在接口中使用常量。 它引入太多的复杂性而没有真正的价值收益。
尝试从实现接口的实际类中解耦包含常量的类。
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); }
@JvmStatic
注释将使属性的后台字段是一个静态的。 也就是说,如果将注释应用于伴随对象中的属性,则将在封闭类中创建新的静态字段。
请注意,Kotlin实际上没有静态的概念,而且这个注释仅仅是针对JVM语言的可访问性。