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

为何Java ArrayList无法转换为继承List的自定义接口?

为什么ArrayList实例无法转换为继承List的自定义接口?

问题场景

我定义了一个继承List的泛型接口,用于3处业务场景并配套构建器:

public interface RefInItemsListInput <T extends Object> extends List<T> {}

另有类RefInItems1的validate方法接收该接口类型的参数:

public static class RefInItems1 extends JsonSchema {
        public static RefInItemsList validate(RefInItemsListInput arg, SchemaConfiguration configuration) throws ValidationException {
            return JsonSchema.validateList(RefInItems1.class, arg, configuration);
        }
}

在JUnit测试中,我尝试将Arrays.asList返回的实例强制转换为RefInItemsListInput:

@Test
public void testPropertyNamedRefValidPasses() {
    // property named $ref valid
    RefInItems.RefInItems1.validate(
        (RefInItems.RefInItemsListInput)
        Arrays.asList(
            MapMaker.makeMap(
                new AbstractMap.SimpleEntry<>(
                    "$ref",
                    "a"
                )
            )
        ),
        configuration
    );
}

运行测试时抛出ClassCastException错误:

java.lang.ClassCastException: class java.util.Arrays$ArrayList cannot be cast to class org.openapijsonschematools.client.components.schemas.RefInItems$RefInItemsListInput (java.util.Arrays$ArrayList is in module java.base of loader 'bootstrap'; org.openapijsonschematools.client.components.schemas.RefInItems$RefInItemsListInput is in unnamed module of loader 'app')

    at org.openapijsonschematools.client.components.schemas.RefInItemsTest.testPropertyNamedRefValidPasses(RefInItemsTest.java:23)
    ...

原因分析

这是Java类型转换的基础规则导致的:

  • 一个对象只能被转换成它实际实现的接口,或者它的父类/父接口类型。
  • Arrays.asList()返回的内部类java.util.Arrays$ArrayList只实现了JDK自带的List、RandomAccess等接口,完全没有实现你自定义的RefInItemsListInput接口。哪怕你的接口继承了List,也只是让它成为List的子接口,并不会让所有List实现类自动兼容这个子接口。

解决方案

方案1:实现包装类(适配器模式)

写一个实现RefInItemsListInput的包装类,把普通List实例包裹进去,转发所有方法调用:

public class RefInItemsListInputWrapper<T> implements RefInItemsListInput<T> {
    private final List<T> delegate;

    public RefInItemsListInputWrapper(List<T> delegate) {
        this.delegate = delegate;
    }

    // 实现List接口的所有方法,直接委托给内部的delegate
    @Override
    public int size() {
        return delegate.size();
    }

    @Override
    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return delegate.contains(o);
    }

    // 其余List接口方法同理实现...
}

测试代码修改为:

RefInItems.RefInItems1.validate(
    new RefInItemsListInputWrapper<>(
        Arrays.asList(
            MapMaker.makeMap(
                new AbstractMap.SimpleEntry<>("$ref", "a")
            )
        )
    ),
    configuration
);

方案2:调整方法参数类型(如果业务允许)

如果RefInItemsListInput只是作为标记接口,没有额外的方法定义,可以直接把validate方法的参数类型改为List<T>,这样就不需要强转,直接传入Arrays.asList的结果即可:

public static RefInItemsList validate(List arg, SchemaConfiguration configuration) throws ValidationException {
    return JsonSchema.validateList(RefInItems1.class, arg, configuration);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:15:22