Java泛型不兼容类型 [英] Java Generics Incompatible Types

查看:89
本文介绍了Java泛型不兼容类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个扩展的抽象类,以及另一个使用它们的类:

----- Base -----

  public abstract class HttpRequest< RESPONSE_TYPE extends HttpResponse> 
{...}
公共抽象类HttpResponse< DATA_TYPE>
{...}



<----> -----扩展-----

  public class MockyTextRequest extends HttpRequest< MockyTextResponse> 
{...}
public class MockyTextResponse extends HttpResponse< TextWithTitle>
{...}

----效用------

  public class HttpClient 
{...
public< REQUEST_TYPE extends HttpRequest< RESPONSE_TYPE>,RESPONSE_TYPE extends HttpResponse< RESULT_TYPE>,RESULT_TYPE> RESPONSE_TYPE synchronicRequest(@NonNull final REQUEST_TYPE httpRequest,@Nullable final Object tag)抛出IOException,HttpException,ParseException
{...}
...}






当我编译时,我得到:


错误:不兼容的类型:推理变量RESPONSE_TYPE有
不兼容的上限HttpResponse,MockyTextResponse

on

  MockyTextResponse httpResponse = HttpClient.get()。synchronicRequest(new MockyTextRequest(),null); 

任何想法?


$ b $
$ b

  public  ; RESULT_TYPE>,RESULT_TYPE> void request(@NonNull final REQUEST_TYPE httpRequest,@Nullable final Object tag,@Nullable final Listener< REQUEST_TYPE,RESPONSE_TYPE> listener)
{...}



  HttpClient.get()。request(new MockyTextRequest( ),MainActivity.this); 

工作正常

github

解决方案

推理算法似乎无法推断 RESPONSE_TYPE 的类型。它看起来像所有三个类型参数应该由 MockyTextRequest 给出。



我并非确切地说确定为什么这是规范的情况,而是与嵌套有关。



错误可以通过以下方式重现:

  //同一行上的错误
/ / C(字符串)不是推断
m(新的ArrayList< List< String>>());

//编译器能够从A
//中推理出B,而不是从A
static ,B extends List< C> ,C> void m(A a){}

这是Java 8中已解决的问题:


  • Ideone Java 7编译

    a>

  • Ideone Java 8编译

  • 您可以提供证人:

    $ c> MockyTextResponse httpResponse =
    HttpClient.get()。
    < MockyTextRequest,MockyTextResponse,TextWithTitle>
    synchronicRequest(new MockyTextRequest(),null);

    或者用几种方法来放宽类型参数:

    <1>


      public< 
    RESPONSE_TYPE扩展了HttpResponse< RESULT_TYPE> ;,
    RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
    final HttpRequest< RESPONSE_TYPE> httpRequest,final Object tag)

    2.

      public< 
    REQUEST_TYPE扩展了HttpRequest< RESPONSE_TYPE> ;,
    RESPONSE_TYPE扩展了HttpResponse<>
    > RESPONSE_TYPE synchronicRequest(
    final REQUEST_TYPE httpRequest,final Object tag)



    <3>

      public< 
    REQUEST_TYPE扩展了HttpRequest< RESPONSE_TYPE> ;,
    RESPONSE_TYPE扩展了HttpResponse<扩展RESULT_TYPE> ;,
    RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
    final REQUEST_TYPE httpRequest,final Object tag)

    从您的描述看来,它似乎像#1是最好的。 (#2和#3基本上是相同的,因为 RESULT_TYPE 不会被推断出来。)




    另一种方法是定义 HttpRequest ,如下所示:

      class HttpRequest< 
    RESPONSE_TYPE扩展了HttpResponse< RESULT_TYPE> ;,
    RESULT_TYPE
    >

    然后:

     类MockyTextRequest 
    扩展HttpRequest< MockyTextResponse,TextWithTitle>

    public<
    REQUEST_TYPE扩展HttpRequest< RESPONSE_TYPE,RESULT_TYPE> ;,
    RESPONSE_TYPE扩展HttpResponse< RESULT_TYPE> ;,
    RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
    final REQUEST_TYPE httpRequest,final Object tag)

    但是这可能会导致一些您的代码更加冗长。






    请注意,您应该避免使用原始类型

      // vvv 
    class HttpRequest< RESPONSE_TYPE extends HttpResponse<>>


    I have 2 abstract classes that are extended, and another class that uses them:

    -----Base-----

    public abstract class HttpRequest<RESPONSE_TYPE extends HttpResponse>
    {...}
    public abstract class HttpResponse<DATA_TYPE>
    {...}
    

    -----Extended-----

    public class MockyTextRequest extends HttpRequest<MockyTextResponse>
    {...}
    public class MockyTextResponse extends HttpResponse<TextWithTitle>
    {...}
    

    ----Utility------

    public class HttpClient
    {...
        public <REQUEST_TYPE extends HttpRequest<RESPONSE_TYPE>, RESPONSE_TYPE extends HttpResponse<RESULT_TYPE>, RESULT_TYPE> RESPONSE_TYPE synchronicRequest(@NonNull final REQUEST_TYPE httpRequest, @Nullable final Object tag) throws IOException, HttpException, ParseException
        {...}
    ...}
    


    When I compile, I get:

    error: incompatible types: inference variable RESPONSE_TYPE has incompatible upper bounds HttpResponse,MockyTextResponse

    on

    MockyTextResponse httpResponse = HttpClient.get().synchronicRequest(new MockyTextRequest(), null);
    

    Any Ideas?


    Stange fact, this call

    public <REQUEST_TYPE extends HttpRequest<RESPONSE_TYPE>, RESPONSE_TYPE extends HttpResponse<RESULT_TYPE>, RESULT_TYPE> void request(@NonNull final REQUEST_TYPE httpRequest, @Nullable final Object tag, @Nullable final Listener<REQUEST_TYPE, RESPONSE_TYPE> listener)
    {...}
    

    called

    HttpClient.get().request(new MockyTextRequest(), MainActivity.this);
    

    Works ok

    Full code here in github

    解决方案

    The inference algorithm seems to not be able to infer the type of RESPONSE_TYPE. It looks like all three type parameters should be given by MockyTextRequest.

    I'm not exactly sure why this is the case with respect to the specification but it has to do with the "nesting".

    The error can be reproduced in the following way:

    // same error on this line
    // C (String) is not inferred
    m(new ArrayList<List<String>>());
    
    // the compiler is able to infer B from A
    // but not C from A
    static <A extends List<B>, B extends List<C>, C> void m(A a) {}
    

    This is the kind of thing that's been fixed in Java 8:

    You could provide a witness:

    MockyTextResponse httpResponse =
        HttpClient.get().
            <MockyTextRequest, MockyTextResponse, TextWithTitle>
            synchronicRequest(new MockyTextRequest(), null);
    

    Or a few ways to loosen up the type parameters:

    1.

    public <
        RESPONSE_TYPE extends HttpResponse<RESULT_TYPE>,
        RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
        final HttpRequest<RESPONSE_TYPE> httpRequest, final Object tag)
    

    2.

    public <
        REQUEST_TYPE extends HttpRequest<RESPONSE_TYPE>,
        RESPONSE_TYPE extends HttpResponse<?>
    > RESPONSE_TYPE synchronicRequest(
        final REQUEST_TYPE httpRequest, final Object tag)
    

    3.

    public <
        REQUEST_TYPE extends HttpRequest<RESPONSE_TYPE>,
        RESPONSE_TYPE extends HttpResponse<? extends RESULT_TYPE>,
        RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
        final REQUEST_TYPE httpRequest, final Object tag)
    

    From your descriptions, it seems like #1 is the best. (#2 and #3 are basically the same because RESULT_TYPE doesn't get inferred anyway.)


    Another way would be to define HttpRequest like the following:

    class HttpRequest<
        RESPONSE_TYPE extends HttpResponse<RESULT_TYPE>,
        RESULT_TYPE
    >
    

    And then:

    class MockyTextRequest
    extends HttpRequest<MockyTextResponse, TextWithTitle>
    
    public <
        REQUEST_TYPE extends HttpRequest<RESPONSE_TYPE, RESULT_TYPE>,
        RESPONSE_TYPE extends HttpResponse<RESULT_TYPE>,
        RESULT_TYPE
    > RESPONSE_TYPE synchronicRequest(
        final REQUEST_TYPE httpRequest, final Object tag)
    

    But this probably makes some of your code a lot more verbose.


    As a side note, you should avoid raw types when you can:

    //                                                  vvv
    class HttpRequest<RESPONSE_TYPE extends HttpResponse<?>>
    

    这篇关于Java泛型不兼容类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆