Preface: I understand generics and how they're declared at the class level (e.g. class MyClass<T>
) but I've never seen it declared at the level of a static method, and without any explicit bindings (e.g. class MySubclass<String> extends MyClass
).
I found this code snippet in an app I'm working on (I didn't write this part). I've never seen a method declared this way. <T>
is not defined anywhere else in the class. Intent.getExtras().get()
returns an Object
which may actually be a String
, Boolean
...etc.
private static <T> T getItemExtra(final Intent intent, final String extraName) {
T item = null;
if(intent != null && intent.getExtras() != null) {
item = (T) intent.getExtras().get(extraName);
}
return item;
}
Sample usage:
String s1 = getItemExtra(someIntent, "some_string_extra");
Uri u1 = getItemExtra(someIntent, "some_uri_extra");
How does the JVM know what type to use for <T>
? (Yes this method compiles and executes successfully).
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
Yes, the angle-brackets with one (or more) types is the syntax for generics. The T (to confirm, can be any identifier) serves as the placeholder for(in effect, is replaced by) the supplied type.
Whenever you want to restrict the type parameter to subtypes of a particular class you can use the bounded type parameter. If you just specify a type (class) as bounded parameter, only sub types of that particular class are accepted by the current generic class. These are known as bounded-types in generics in Java.
Well there's no difference between the first two - they're just using different names for the type parameter ( E or T ).
How does the JVM know what type to use for
<T>
?
The basic answer is, it doesn't. In Java, generic types are used by the type checker at compile time, but are removed from the program when the program actually runs. So for instance, the cast to T
in item = (T) intent.getExtras().get(extraName)
doesn't actually do anything at runtime: it's effectively a cast to Object
, always, regardless of what type the caller expects T
to be. (This is different from a cast to a normal type like String
, where the program will fail with an exception immediately if you try to cast the wrong thing.)
The fact that you can cast to T
without a check is a loophole in Java's type system that can cause weird class-cast exceptions. For instance, if you say
String s = getItemExtra(...);
s.toLowerCase();
but getItemExtra
doesn't return a string, then you'll get an exception on the second line telling you that s
isn't a string, even though there's no cast on that line. For that reason, when the Java compiler sees a cast to T
it will generate an unchecked-cast warning, telling you that it can't check that your typecast was legal and you might run into problems like this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With