相关疑难解决方法(0)

Java泛型类型擦除:何时以及发生了什么?

在Oracle的网站上读到了Java的类型擦除.

什么时候发生类型擦除?在编译时还是运行时?当班级加载?当类被实例化时?

很多站点(包括上面提到的官方教程)都说在编译时会发生类型擦除.如果在编译时完全删除了类型信息,那么当调用使用泛型的方法而没有类型信息或错误的类型信息时,JDK如何检查类型兼容性?

考虑以下示例:Say class A有一个方法,empty(Box<? extends Number> b).我们编译A.java并获取类文件A.class.

public class A {
    public static void empty(Box<? extends Number> b) {}
}
Run Code Online (Sandbox Code Playgroud)
public class Box<T> {}
Run Code Online (Sandbox Code Playgroud)

现在我们创建另一个类B,该类empty使用非参数化参数(原始类型)调用该方法:empty(new Box()).如果我们编译B.javaA.class在类路径中,javac的是足够聪明,引发警告.所以A.class 一些类型信息存储在其中.

public class B {
    public static void invoke() {
        // java: unchecked method invocation:
        //  method empty in class A is applied to given types
        //  required: Box<? extends java.lang.Number>
        //  found: …
Run Code Online (Sandbox Code Playgroud)

java generics type-erasure

233
推荐指数
6
解决办法
8万
查看次数

何时在Kotlin中使用内联函数?

我知道内联函数可能会提高性能并导致生成的代码增长,但我不确定何时正确使用它.

lock(l) { foo() }
Run Code Online (Sandbox Code Playgroud)

编译器可以发出以下代码,而不是为参数创建函数对象并生成调用.(来源)

l.lock()
try {
  foo()
}
finally {
  l.unlock()
}
Run Code Online (Sandbox Code Playgroud)

但我发现kotlin没有为非内联函数创建的函数对象.为什么?

/**non-inline function**/
fun lock(lock: Lock, block: () -> Unit) {
    lock.lock();
    try {
        block();
    } finally {
        lock.unlock();
    }
}
Run Code Online (Sandbox Code Playgroud)

function inline-functions kotlin

87
推荐指数
5
解决办法
2万
查看次数

为什么 Kotlin 中有 reified 关键字,将函数标记为内联还不够吗?

在 Kotlin 中,鉴于“reified”关键字只能用于内联函数的泛型类型参数,为什么还要有 reified 关键字呢?为什么 Kotlin 编译器(至少在未来)不能自动将内联函数的所有泛型类型参数视为具体化?

我发现人们在看到这个“具体化”一词时感到恐慌,并要求我不要使代码变得复杂。因此就有了这个问题。

kotlin kotlin-reified-type-parameters

8
推荐指数
1
解决办法
2636
查看次数

Kotlin:返回一个通用接口

在 Kotlin 中,我正在尝试编译以下内容:

  1. 给定一个具有泛型类型的接口(打印机)
  2. 以及该接口的两个实现(DogPrinter 和 CatPrinter)
  3. 根据外部变量(AnimalType)返回其中一台打印机

以下代码无法编译,因为在以下位置需要类型: fun getMapper(animalType: AnimalType): Printer

我尝试使用<Any>or<*>但没有成功。有人可以帮忙吗?

(通过将下面的代码复制粘贴到https://try.kotlinlang.org很容易看到错误

enum class AnimalType {
    CAT, DOG
}

class Dog
class Cat

interface Printer<in T> {
    fun mapToString(input: T): String
}


class DogPrinter : Printer<Dog> {
    override fun mapToString(input: Dog): String {
        return "dog"
    }
}

class CatPrinter : Printer<Cat> {
    override fun mapToString(input: Cat): String {
        return "cat"
    }
}

private fun getMapper(animalType: AnimalType): Printer {
    return when(animalType) …
Run Code Online (Sandbox Code Playgroud)

generics kotlin

6
推荐指数
1
解决办法
5170
查看次数

如果你只有一个 KClass 对象,用 reified 类型参数调用一个 fun 吗?

只能将具体化的类型参数与内联函数一起使用。所以如果我想要一个类的这样的参数,我需要一个这样的技巧:

class Foo<T : Any>(private val clazz: KClass<T>) {
    companion object {
        inline fun <reified T: Any> create() = Foo(T::class)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我可以创建这样的实例Foo

val foo = Foo.create<Bar>()
Run Code Online (Sandbox Code Playgroud)

Foo我可以访问clazz但我的问题是clazz当我需要调用需要具体化类型参数的方法时我可以使用吗?

例如,Foo我想添加一个这样的方法:

fun print(list: List<Alpha>) {
    list.filterIsInstance<T>().forEach { print(it) }
}
Run Code Online (Sandbox Code Playgroud)

但据我所知,没有办法从 clazz这里可以用作类型参数的东西。

是的,我知道有一种形式filterIsInstance需要 aClass所以我可以这样做:

list.filterIsInstance(clazz.java).forEach { print(it) }
Run Code Online (Sandbox Code Playgroud)

然而,许多库都包含两种形式(显式类参数和具体化类型参数)的方法 提供。

例如 Jackson Kotlin Extensions.kt。实际上这不是一个很好的例子,因为非具体化的等价物都是单行的,但情况并非总是如此——然后你最终将具体化类型参数方法的实现解包到你的代码中。

generics kotlin kotlin-reified-type-parameters

6
推荐指数
1
解决办法
879
查看次数

协程内部的通用泛型参数不起作用

我正在创建http json客户端。我将Volley与协程结合使用。我想创建通用的HTTP客户端,以便可以在任何地方使用它。

我创建了通用扩展方法来将JSON字符串解析为对象。

inline fun <reified T>String.jsonToObject(exclusionStrategy: ExclusionStrategy? = null) : T {
val builder = GsonBuilder()

if(exclusionStrategy != null){
    builder.setExclusionStrategies(exclusionStrategy)
}

return builder.create().fromJson(this, object: TypeToken<T>() {}.type)
Run Code Online (Sandbox Code Playgroud)

}

问题是,当我调用此方法时,无法得到预期的结果。第一次通话会给出正确的结果。对象已初始化。但是第二次调用(我使用传递给方法的通用参数)以异常“ LinkedTreeMap无法转换为令牌”结束。

    protected inline fun <reified T>sendRequestAsync(endpoint: String, data: Any?, method: Int, token: Token?): Deferred<T> {
    return ioScope.async {
        suspendCoroutine<T> { continuation ->
            val jsonObjectRequest = HttpClient.createJsonObjectRequest(
                endpoint,
                data?.toJsonString(),
                method,
                Response.Listener {
                    //this call is successful and object is initialized
                    val parsedObject : HttpResponse<Token> = it.toString().jsonToObject()

                    //this call is not successful and …
Run Code Online (Sandbox Code Playgroud)

java generics coroutine kotlin

6
推荐指数
1
解决办法
211
查看次数

Kotlin将类型函数作为函数扩展来实现 - 可以从Java调用吗?

我正在尝试使用具有reified类型的函数作为扩展函数,但我不认为这是可能的,因为在我检查生成的字节码后我发现方法签名是私有的,是否有任何解决方法使其公开?

CommonExtensions.kt

inline fun<reified T: Activity> Context.startActivity() {
    val intent = Intent(this, T:: class.java)
    startActivity(intent)
}

fun View.visible() {
    visibility = View.VISIBLE
}
Run Code Online (Sandbox Code Playgroud)

Kotlin字节码:

private final static startActivity(Landroid/content/Context;)V
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   ...
Run Code Online (Sandbox Code Playgroud)

客户代码:

Kotlin文件

override fun showMessageEmptyOfferFeeds() {
        mOfferFeedsWarning.visible() // "visible()" extension func RESOLVED
}
Run Code Online (Sandbox Code Playgroud)

Java文件

showProfileDetailsUi(){
   startActivity<DetailActivity>() //"startActivity()" extension func NOT RESOLVED
}
Run Code Online (Sandbox Code Playgroud)

java kotlin kotlin-android-extensions kotlin-reified-type-parameters

5
推荐指数
1
解决办法
672
查看次数

类型擦除如何工作

我正在调查创建代理对象的库是如何工作的,特别是我想了解它们如何从声明的方法中获取类型.例如Android的流行库 - Retrofit:

interface MyService {

    @GET("path")
    Call<MyData> getData();
}
Run Code Online (Sandbox Code Playgroud)

我很困惑 - 如何才能从这个界面获得正确的MyData类而不是原始对象?我的理解类型擦除的原因将删除放置在通用大括号内的任何信息.

我写了一些测试代码,令我惊讶的是从这样的代码获取类型真的很容易:

@org.junit.Test
public void run() {
    Method[] methods = Test.class.getDeclaredMethods();
    Method testMethod = methods[0];
    System.out.println(testMethod.getReturnType());
    ParameterizedType genericType = ((ParameterizedType) testMethod.getGenericReturnType());
    Class<Integer> clazz = (Class<Integer>) genericType.getActualTypeArguments()[0];
    System.out.println(clazz);
}

interface Test {
    List<Integer> test();
}
Run Code Online (Sandbox Code Playgroud)

它看起来有点脏,但它的工作和打印Integer.这意味着我们在运行时有类型.此外,我已经阅读了有关匿名类的另一个脏技巧:

System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass());
Run Code Online (Sandbox Code Playgroud)

AbstractList<E>这段代码打印原始

System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass());
Run Code Online (Sandbox Code Playgroud)

打印ArrayList<Integer>.

这并不是让我困惑的最后一件事.在Kotlin中有一些具体的泛型,在编译时看起来像是一些黑客,但我们可以轻松地从泛型中获取类:

inline fun <reified T> test() {
    print(T::class)
}
Run Code Online (Sandbox Code Playgroud)

而现在我完全混淆了类型擦除机制.

  1. 有人可以解释一下,为什么有时它会保存信息而有时却没有?
  2. 为什么在Java中没有以正常方式实现泛型?是的,我读到它可能会破坏先前版本的兼容性,但我想了解如何.为什么泛型返回类型不会破坏任何东西但是new ArrayList<Integer>呢?
  3. 为什么匿名类包含泛型类型而不是类型擦除?

更新: 4.如何在Kotlin中使用具体化的泛型以及为什么这样的酷事不能用Java实现?

这里解释了如何使用仿制药. …

java generics jvm kotlin

5
推荐指数
1
解决办法
230
查看次数

如何在Kotlin的Gson注册InstanceCreator?

我可以使用MutableList<MDetail>Gson正确地使用代码1保存到json字符串,但是当我尝试MutableList<MDetail>使用代码2从json字符串恢复对象时出现错误。我搜索了一些资源,看来我需要注册InstanceCreator。

如何InstanceCreator用Kotlin 写一个注册码?谢谢!

错误

Caused by: java.lang.RuntimeException: Unable to invoke no-args constructor for interface model.DeviceDef. Registering an InstanceCreator with Gson for this type may fix this problem.
Run Code Online (Sandbox Code Playgroud)

代码1

private var listofMDetail: MutableList<MDetail>?=null
mJson = Gson().toJson(listofMDetail) //Save
Run Code Online (Sandbox Code Playgroud)

代码2

var mJson: String by PreferenceTool(this, getString(R.string.SavedJsonName) , "")
var aMListDetail= Gson().fromJson<MutableList<MDetail>>(mJson)

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
Run Code Online (Sandbox Code Playgroud)

我的课

interface DeviceDef

data class BluetoothDef(val status:Boolean=false):  DeviceDef
data class WiFiDef(val name:String, val status:Boolean=false) : …
Run Code Online (Sandbox Code Playgroud)

java json gson kotlin

5
推荐指数
1
解决办法
2707
查看次数

适用于Android项目的BaseFragment体系结构

我正在开始一个新项目,我将与10个开发人员组成一个团队。我正在为我们的Android应用设置基础结构。在与团队合作时,我希望每个人都遵循相同的结构,即为ViewModel每个人创建fragment并使用数据绑定。我如何使其严格,以使开发人员在未ViewModel为其片段创建代码时出错?

所以我创建了以下内容BaseFragment

abstract class BaseFragment<out VM : BaseViewModel, DB : ViewDataBinding> : Fragment() {

    open lateinit var binding: DB

    private fun init(inflater: LayoutInflater, container: ViewGroup?) {
        binding = DataBindingUtil.inflate(inflater, getLayoutRes(), container, false)
    }

    @LayoutRes
    abstract fun getLayoutRes(): Int

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        init(inflater, container)
        super.onCreateView(inflater, container, savedInstanceState)
        return binding.root
    }

    open fun refresh() {}
}
Run Code Online (Sandbox Code Playgroud)

我该如何进一步改善?

android android-fragments kotlin android-architecture-components

5
推荐指数
1
解决办法
371
查看次数

如何检查 Kotlin 函数内的泛型类型?

我正在使用 Kotlin 来解析 JSON。例如,我有一个国家的表示:{"code":"US", "name":"United States of America"}Country为了从这样的 a生成一个对象JSONObject,我有这个函数:

val produceCountry = fun (js: JSONObject) =
        Country(js.getString("code"), js.getString("name"))
Run Code Online (Sandbox Code Playgroud)

我可以使用这个函数轻松解析数组Country。然而,除了 数组之外Country,我还有CatCarCartCordlessPhone等数组。每个数组都有自己的produce*函数,将 a 转换JSONObject为该类型的 Kotlin 对象。为了概括数组解析,我有这个函数:

fun <T> produceSetOf(array: JSONArray, element: (JSONObject) -> T): Set<T> {
    val set = mutableSetOf<T>()

    for (i in 0 until array.length())
        set.add(element(array.getJSONObject(i)))

    return set
}
Run Code Online (Sandbox Code Playgroud)

所以我可以调用produceSetOf(jsonArray, produceCountry)遇到一个元素类型为 的数组Country。这也适用于Cat, Car …

arrays json higher-order-functions kotlin

3
推荐指数
1
解决办法
4234
查看次数

为什么 Kotlin reified 函数更好?

Kotlin 官方文档这个答案很好地解释了 Kotlin 如何reified让我们改变以下内容:

myJsonString.toData(MyDataClass::class)
Run Code Online (Sandbox Code Playgroud)

到:

myJsonString.toData<MyDataClass>()
Run Code Online (Sandbox Code Playgroud)

但我认为两者都不能很好地解释动机。reified 函数只是因为它节省了几个字符而更可取吗?或者不必将类作为参数传递还有其他好处吗?

kotlin

2
推荐指数
1
解决办法
243
查看次数