That trick "works" in Java because, for compatibility reasons (Java didn't have generics originally), the generic type is erased by the compiler. Your example compiles to:
static List listOfAnything() { return (List) new ArrayList(); }
List stringList = listOfAnything();
List listOfInts() { return listOfAnything(); }
The generic type isn't monomorphised or even reified; within your method, you don't have access to the generic type T "passed" by the caller. If you need it, you have to pass it explicitly, as commonly used by deserialization libraries:
static <T> T deserialize(String input, Class<T> cls) { ... }
Which can be used like this:
MyStruct result = deserialize(input, MyStruct.class);
Note that the deserialization library has no way of knowing the type of the variable the caller is putting the result in, the caller had to pass it explicitly. This is because what the Java compiler actually generated from the code above was something like:
static Object deserialize(String input, Class cls) { ... }
MyStruct result = (MyStruct) deserialize(input, MyStruct.class);
It's possible for the deserialization library to know the type from the payload itself, but of course it has to "happen" to coincide with what's being cast to. You don't need to pass the Class object at all.
Generics are awesome. They allow you to do partial typing. You don't specify the exact type but you constrain the output type based on the input type. So you have functions that can operate on many types but still have strong typing.
Wantarray is not a generic implementation. It's closer to reflection. You can detect the type of variable the caller is putting your functions result in. Then you can branch your program based on the variable type that the caller wants. I guess this is similar to type inference but not exactly as it's not part of the type system. For example, if they want an array return the amounts of each transaction in an array if not return the sum of the transaction amounts.
And that well-studied for of polymorphism is entirely unlike having the callee knowing if the caller expects an array or an it, and changing the result.
You can do that in Java, if I understand that feature correctly.
For example, it's possible to write a method that returns a generic type over whatever type you're trying to assign to, e.g.:
Which can be used like this: Or by letting the compiler infer the type from the return type of a method: This is not just some esoteric feature... it's quite commonly used by, for example, deserialization libraries and functional programming.