Java's implementation of generics uses erased types. Consequently, there is not actually any runtime implementation difference between, say, a List<Integer>
and a List<String>
. The virtual machine representation of both types is actually just List<Object>
. From within Mathematica, we need not (and cannot) explicitly express any generic type parameters. We must work with generic types as if all type parameters were Object
, remaining silent as to generic types. So, for example:
Needs["JLink`"]
InstallJava[];
LoadJavaClass["java.util.Collections"];
JavaBlock@Module[{list}
, list = Collections`emptyList[]
; list@size[]
]
(* 0 *)
JavaBlock@Module[{list}
, list = JavaNew["java.util.ArrayList"]
; list@add[MakeJavaObject@#]& /@ Range[5]
; Collections`reverse[list]
; JavaObjectToExpression[list]
]
(* {5,4,3,2,1} *)
In the second example, take note that we had to explicitly convert the integers into Java objects using MakeJavaObject
. If we had not, then JLink would have looked for a non-existent method with the signature ArrayList#add(int)
instead of the valid method ArrayList#add(Object)
.
JLink, unlike a Java compiler, does not offer any "compile time" checking of generic type arguments. So the burden is passed to us to make sure that we are creating generic parameters that are type-compatible with whatever API we are calling. If an API calls for a List<String>
, and we pass a List<Integer>
, the API will simply behave badly at runtime. If we are lucky, it will fail outright with a ClassCastException
. If we are unlucky, it could just malfunction quietly and subtly. Take care to match the required types.