Let’s say we have some interface like this:
public interface Foo<T> { <TIn extends T> void encode(TIn value) T decode() }
I’m using Foo a lot in my codebase, but I wish to add the TIn extends T
to make it more flexible, to eg have a Foo<Map<X>>
able to encode
a HashMap<X>
or a TreeMap<X>
.
This works really well – until I tried to implement Foo<T[]>
, where it seems to be impossible to implement, with public <TIn extends TItem[]> void encode(TIn array)
giving a parse error “> expected
” when it hits the brackets []
. Even IntelliJ does nothing when it volunteers to implement the interface.
For what it’s worth, if T is some other concrete final type (eg byte[], Boolean, etc), it seems that I can satisfy the interface by just returning T, so it seems to do some hidden intelligent fixing here. So it seems that it’s just a problem with T[]
where it can’t detect T[]
is final.
Does anyone have any ideas about how I can workaround this? I don’t really care that TIn extends byte[]
can only be met with TIn = byte[]
, I just want to implement the interface for the compiler to be happy; and so that this interface can be used elsewhere.
Advertisement
Answer
None of this makes sense. You don’t need that TIn
in the first place:
public interface Foo<T> { void encode(T value); T decode; } class Example { void test() { Foo<HashMap<String, Integer>> foo = null; foo.encode(new HashMap<String, Integer>()); } }
This compiles just fine. In general if you declare a new typevar that is used in only 1 place, it’s pointless – typevars are solely a thing javac
worries about, the runtime doesn’t know what generics (typevars) are. Hence, it doesn’t make much sense to use them unless they serve to link 2 different places where a type is mentioned, e.g. ‘the type of parameter to the encode method, the return type of the decode() method? I don’t care what it is, but, for any given usage of the Foo
type, it’s the same – that kind of ‘linking’).
Given that there’s no need to introduce an additional type param on the encode
method, there’s no need to try to declare a new type var there.
The usual alternative to a typevar that is used in just a single location is ?
. There is no functional difference between <F> void foo(List<F> in)
and void foo(List<?> in)
.