Java Generics Puzzler, extending a class and using wildcards

前端 未结 6 1852
不知归路
不知归路 2021-01-31 02:02

I\'ve been beating my head against this one for awhile and thought that maybe some fresh eyes will see the issue; thanks for your time.

import java.util.*;

clas         


        
6条回答
  •  自闭症患者
    2021-01-31 02:24

    This happens because of the way capture conversion works:

    There exists a capture conversion from a parameterized type G1,...,Tn> to a parameterized type G1,...,Sn>, where, for 1 ≤ i ≤ n :

    • If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable [...].

    Capture conversion is not applied recursively.

    Note the end bit. So, what this means is that, given a type like this:

        Map>
    //      │  │    └ no capture (not applied recursively)
    //      │  └ T2 is not a wildcard
    //      └ T1 is a wildcard
    

    Only "outside" wildcards are captured. The Map key wildcard is captured, but the List element wildcard is not. This is why, for example, we can add to a List>, but not a List. The placement of the wildcard is what matters.

    Carrying this over to TbinList, if we have an ArrayList>, the wildcard is in a place where it does not get captured, but if we have a TbinList, the wildcard is in a place where it gets captured.

    As I alluded to in the comments, one very interesting test is this:

    ArrayList> test3 = new TbinList<>();
    

    We get this error:

    error: incompatible types: cannot infer type arguments for TbinList<>
        ArrayList> test3 = new TbinList<>();
                                                            ^
        reason: no instance(s) of type variable(s) T exist so that
                TbinList conforms to ArrayList>

    So there's no way to make it work as-is. One of the class declarations needs to be changed.


    Additionally, think about it this way.

    Suppose we had:

    class Derived1 extends Base {}
    class Derived2 extends Base {}
    

    And since a wildcard allows subtyping, we can do this:

    TbinList test4 = new TbinList();
    

    Should we be able to add a Tbin to test4? No, this would be heap pollution. We might end up with Derived2s floating around in a TbinList.

提交回复
热议问题