What is a generic method and how is <T> related in this case?

Preface: I understand generics and how they are declared at the class level (e.g. class MyClass<T> ), but I have never seen it declared at the static method level and without any explicit bindings (e.g. class MySubclass<String> extends MyClass ).

I found this piece of code in the application I'm working on (I did not write this part). I have never seen a method declared this way. <T> 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 which type to use for <T> ? (Yes, this method compiles and runs successfully).

+5
source share
3 answers

This is what is known in Java as a generic method . T in represents the type you usually specify. Then the compiler will replace any instances of T with the type you replaced. If you do not, the compiler will try to infer the correct type from the available information.

For a more detailed explanation, you should study Java Generics .

+1
source

How does the JVM know which type to use for <T> ?

The main answer is no. In Java, generic types are used by the type checking tool at compile time, but are removed from the program when the program actually runs. So, for example, casting to T to item = (T) intent.getExtras().get(extraName) actually does nothing at runtime: it is effectively casting to Object , always, no matter what type of caller expects T (This is different from casting to a normal type of type String , where the program will crash immediately if you try to do the wrong thing.)

The fact that you can use T without checking is a loophole in the Java type system, which can cause strange exceptions for the class. For example, if you say

 String s = getItemExtra(...); s.toLowerCase(); 

but getItemExtra does not return a string, then in the second line you will get an exception indicating that s not a string, even if there is not a single line in this string. For this reason, when the Java compiler sees a cast in T , it will generate a warning without a mark, telling you that it cannot verify that your type was legal, and you may encounter such problems.

+3
source

T is what is known as a type interface. In this case, the return type is the type interface, so just saying that getItemExtra(...) will return a String or Uri is enough for the compiler to know that this method will return this object. However, this is not a good example for entering type interfaces, so here is a simpler example.

ArrayList is implemented using a type interface, except that you tell ArrayList what type of object it will contain, except they use E instead of T , which is fine because the character is arbitrary as long as you use the same character in your entire implementation.

Here is the relevant snippet from the actual implementation :

 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { 

So, if you declare an ArrayList<String> , the compiler will replace E with String at compile time. The same goes for ArrayList<YourCustomObject> , it will replace E with YourCustomObject throughout the implementation.

+1
source

Source: https://habr.com/ru/post/1235748/


All Articles