You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin泛型Retrofit函数调用抛出ClassCastException问题排查

问题根源与解决方案

核心原因

这个错误的本质是泛型类型擦除导致的:Java在运行时会擦除泛型的具体类型信息,Retrofit和Gson无法得知你指定的Standings类型,只能将JSON响应默认解析成LinkedTreeMap(Gson处理未知类型的默认行为)。当你尝试把这个LinkedTreeMap强制转换成retrofit2.Response<Standings>时,就会触发ClassCastException。

常见的错误场景包括:

  • 接口定义了泛型方法,但没有提供足够的类型信息让Retrofit/Gson识别目标类型
  • 错误地将接口返回值强转为不匹配的泛型类型
  • 接口方法的返回值类型定义模糊(比如用Call<Object>代替Call<Response<Standings>>)

修复方案

方案1:为每个实体类定义独立接口方法(推荐)

直接避免泛型擦除问题,明确指定每个接口方法的返回类型:

public interface LeagueApi {
    // 获取Standings类型的响应
    @GET("standings")
    Call<Response<Standings>> getLeagueStandings();

    // 获取Standings2类型的响应
    @GET("standings")
    Call<Response<Standings2>> getLeagueStandings2();
}

调用时无需指定泛型,Retrofit会直接根据方法定义解析出正确的实体类实例:

leagueApi.getLeagueStandings().enqueue(new Callback<Response<Standings>>() {
    @Override
    public void onResponse(Call<Response<Standings>> call, retrofit2.Response<Response<Standings>> response) {
        if (response.isSuccessful()) {
            Response<Standings> standingsResponse = response.body();
            // 正常处理Standings实例
        }
    }

    @Override
    public void onFailure(Call<Response<Standings>> call, Throwable t) {
        // 处理错误
    }
});

方案2:使用接口级泛型(适合复用逻辑场景)

如果需要复用接口逻辑,可以将泛型定义在接口级别,创建实例时指定具体类型:

public interface LeagueApi<T> {
    @GET("standings")
    Call<Response<T>> getLeagueStandings();
}

创建接口实例时明确传入Standings类型:

LeagueApi<Standings> standingsApi = retrofit.create(LeagueApi.class);
standingsApi.getLeagueStandings().enqueue(new Callback<Response<Standings>>() {
    // 回调逻辑同方案1
});

方案3:显式传递类型信息(复杂泛型场景)

如果必须使用泛型方法,需要通过TypeToken显式告诉Gson目标类型。这种方式需要手动解析响应体:

// 定义泛型方法,返回原始ResponseBody
public interface LeagueApi {
    @GET("standings")
    Call<ResponseBody> getLeagueStandings();
}

调用时手动解析,用TypeToken明确泛型类型:

leagueApi.getLeagueStandings().enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
        if (response.isSuccessful()) {
            try {
                String json = response.body().string();
                // 用TypeToken指定Response<Standings>的具体类型
                Type type = new TypeToken<Response<Standings>>(){}.getType();
                Response<Standings> standingsResponse = new Gson().fromJson(json, type);
                // 处理实例
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {
        // 处理错误
    }
});

内容的提问来源于stack exchange,提问作者Ahmed Gamal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 07:22:40