java - How do generics of generics work? -


while understand of corner-cases of generics, i'm missing following example.

i have following class

1 public class test<t> { 2   public static void main(string[] args) { 3     test<? extends number> t = new test<bigdecimal>(); 4     list<test<? extends number>> l =collections.singletonlist(t); 5   } 6 } 

line 4 gives me error

type mismatch: cannot convert list<test<capture#1-of ? extends number>>  list<test<? extends number>>`.  

obviously, compiler thinks different ? not equal. while gut-feeling tells me, correct.

can provide example runtime-error if line 4 legal?

edit:

to avoid confusion, replaced =null in line 3 concrete assignment

as kenny has noted in comment, can around with:

list<test<? extends number>> l =     collections.<test<? extends number>>singletonlist(t); 

this tells operation isn't unsafe, it's victim of limited inference. if unsafe, above wouldn't compile.

since using explicit type parameters in generic method above ever necessary act hint, can surmise being required here technical limitation of inference engine. indeed, java 8 compiler slated ship many improvements type-inference. i'm not sure whether specific case resolved.

so, what's happening?

well, compile error we're getting shows type parameter t of collections.singletonlist being inferred capture<test<? extends number>>. in other words, wildcard has metadata associated links specific context.

  • the best way think of capture of wildcard (capture<? extends foo>) unnamed type parameter of same bounds (i.e. <t extends foo>, without being able reference t).
  • the best way "unleash" power of capture binding named type parameter of generic method. i'll demonstrate in example below. see java tutorial "wildcard capture , helper methods" (thanks reference @wchargin) further reading.

say want have method shifts list, wrapping back. let's assume our list has unknown (wildcard) type.

public static void main(string... args) {     list<? extends string> list = new arraylist<>(arrays.aslist("a", "b", "c"));     list<? extends string> cycledtwice = cycle(cycle(list)); }  public static <t> list<t> cycle(list<t> list) {     list.add(list.remove(0));     return list; } 

this works fine, because t resolved capture<? extends string>, not ? extends string. if instead used non-generic implementation of cycle:

public static list<? extends string> cycle(list<? extends string> list) {     list.add(list.remove(0));     return list; } 

it fail compile, because haven't made capture accessible assigning type parameter.

so begins explain why consumer of singletonlist benefit type-inferer resolving t test<capture<? extends number>, , returning list<test<capture<? extends number>>> instead of list<test<? extends number>>.

but why isn't 1 assignable other?

why can't assign list<test<capture<? extends number>>> list<test<? extends number>>?

well if think fact capture<? extends number> equivalent of anonymous type parameter upper bound of number, can turn question "why doesn't following compile?" (it doesn't!):

public static <t extends number> list<test<? extends number>> assign(list<test<t>> t) {     return t; }  

this has reason not compiling. if did, possible:

//all valid list<test<double>> doubletests = null; list<test<? extends number>> numbertests = assign(doubletests);  test<integer> integertest = null; numbertests.add(integertest); //type error, doubletests contains test<integer> 

so why being explicit work?

let's loop beginning. if above unsafe, how come allowed:

list<test<? extends number>> l =     collections.<test<? extends number>>singletonlist(t); 

for work, implies following allowed:

test<capture<? extends number>> capturedt; test<? extends number> t = capturedt; 

well, isn't valid syntax, can't reference capture explicitly, let's evaluate using same technique above! let's bind capture different variant of "assign":

public static <t extends number> test<? extends number> assign(test<t> t) {     return t; }  

this compiles successfully. , it's not hard see why should safe. it's use case of

list<? extends number> l = new list<double>(); 

Comments

Popular posts from this blog

java - Jmockit String final length method mocking Issue -

asp.net - Razor Page Hosted on IIS 6 Fails Every Morning -

c++ - wxwidget compiling on windows command prompt -