【问题标题】:Java generics with wildcard not compiling带有通配符的 Java 泛型无法编译
【发布时间】:2017-01-18 08:46:27
【问题描述】:

我用我的真实代码做了这个简化的例子,它没有编译:

public class Example {

    public static void main(String[] args) {
        Callback<BalanceResponse> balanceRequestCaller = new Callback<BalanceResponse>() {
            @Override
            public void onResponse(BalanceResponse response) {}

            @Override
            public void onFailure(String error, int code) {}

            @Override
            public void onFailure(Throwable t) {}
        };

        BalanceRequest breq = new BalanceRequest();

        Interceptor interceptor = new Interceptor(balanceRequestCaller);

        breq.startRequest((Callback<BaseResponse>) interceptor); //compile-time error!!!
    }


    public static class Interceptor implements Callback<BaseResponse> {

        public Interceptor(Callback<? extends BaseResponse> originalCaller) {
            this.originalCaller = originalCaller;
        }

        private Callback<? extends BaseResponse> originalCaller;

        @Override
        public void onResponse(BaseResponse response) {
            //do some interception stuff

            if (response instanceof BalanceResponse) {
                ((Callback<BalanceResponse>) originalCaller).onResponse((BalanceResponse) response);
            } else if (response instanceof SubscriptionResponse) {
                ((Callback<SubscriptionResponse>) originalCaller).onResponse((SubscriptionResponse) response);
            }
        }

        @Override
        public void onFailure(String error, int code) {}

        @Override
        public void onFailure(Throwable t) {}
    }

    public interface Request<T extends BaseResponse> {
        void startRequest(Callback<T> callback);
    }

    public static class BalanceRequest implements Request<BalanceResponse> {
        @Override
        public void startRequest(Callback<BalanceResponse> callback) {}
    }

    public static class SubscriptionRequest implements Request<SubscriptionResponse> {
        @Override
        public void startRequest(Callback<SubscriptionResponse> callback) {}
    }

    public static class BaseResponse {
        public String status;
    }

    public static class BalanceResponse extends BaseResponse {

    }

    public static class SubscriptionResponse extends BaseResponse {

    }

    public interface Callback<T> {
        void onResponse(T response);
        void onFailure(String error, int code);
        void onFailure(Throwable t);
    }
}

我要做的是创建一个Interceptor 来拦截回调,对响应做一些事情,然后将其传递给原始回调。

我想创建一个通用的Interceptor,它可以拦截任何Callback&lt;? extends BaseResponse&gt; 的回调。

顺便说一下,我从 NetBeans 得到的编译时错误是

incompatible types: Callback<BaseResponse> cannot be converted to Callback<BalanceResponse>

给我一​​些建议,我怎样才能做到这一点?

【问题讨论】:

    标签: java generics compiler-errors callback wildcard


    【解决方案1】:

    您应该在您的类Interceptor 上定义一个类型参数,以防止您的编译错误并避免在方法onResponse 中显式强制转换,这通常是设计问题的证明。

    带有类型参数的拦截器类

    public static class Interceptor<T extends BaseResponse> implements Callback<T> {
    
        public Interceptor(Callback<T> originalCaller) {
            this.originalCaller = originalCaller;
        }
    
        private Callback<T> originalCaller;
    
        @Override
        public void onResponse(T response) {
            originalCaller.onResponse(response);
        }
    
        ...
    }
    

    然后您将实例化它并将其用作下一个:

    Interceptor<BalanceResponse> interceptor = new Interceptor<>(balanceRequestCaller);
    breq.startRequest(interceptor);
    

    【讨论】:

      【解决方案2】:

      startRequest()签名的签名改为

      void startRequest(Callback<? super T> callback);
      

      这允许它接受更通用的回调,而不是只需要最窄的类型。欲了解更多信息,请参阅What is PECS (Producer Extends Consumer Super)?

      编辑:@teppic's answer 是更好的解决方案,除非您必须为不同的请求类型重用单个 Interceptor 实例。如果是这种情况,您仍然可以将样板文件简化为单个委托:

      @Override
      public void onResponse(BaseResponse response) {
          //do some interception stuff
          ((Callback<BaseResponse>)originalCaller).onResponse(response);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多