What is a generic method and how is bound in this case?
前言:我理解泛型以及它们是如何在类级别声明的(例如class MyClass< T >)但我从未在静态方法的级别上声明它,并且没有任何显式绑定(例如class MySubclass extends MyClass)。
我在我正在处理的应用程序中找到了这段代码片段(我没有写这部分)。 我从未见过以这种方式声明的方法。 < T >未在班级中的任何其他位置定义。 Intent.getExtras().get()返回Object,实际上可能是String,Boolean ......等。
1 2 3 4 5 6 7 8 9
| 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 ;
} |
样品用法:
1 2
| String s1 = getItemExtra (someIntent, "some_string_extra");
Uri u1 = getItemExtra (someIntent, "some_uri_extra"); |
JVM如何知道< T >使用什么类型? (是的,此方法编译并成功执行)。
-
不是远程问题的另一个问题。
-
@Nilish我问的是泛型方法,而不是泛型类。 我已经更新了问题以反映这一点。
-
@OliverGond?是的我必须承认这是重复的。
How does the JVM know what type to use for < T >?
基本的答案是,它没有。在Java中,类型检查器在编译时使用泛型类型,但在程序实际运行时将从程序中删除。因此,例如,item = (T) intent.getExtras().get(extraName)中T的强制转换实际上并没有在运行时执行任何操作:无论调用者期望T是什么类型,它总是有效地转换为Object。 (这与强制类型转换为普通类型如String不同,如果你试图抛出错误的东西,程序将立即失败并出现异常。)
您可以在不进行检查的情况下转换为T这一事实是Java类型系统中的一个漏洞,它可能导致奇怪的类转换异常。例如,如果你说
1 2
| String s = getItemExtra (... );
s. toLowerCase(); |
但getItemExtra不会返回一个字符串,那么你会在第二行得到一个异常,告诉你s不是一个字符串,即使该行没有强制转换。因此,当Java编译器看到转换为T时,它将生成一个未经检查的强制转换警告,告诉您它无法检查您的类型转换是否合法,并且您可能会遇到类似这样的问题。
-
实际上,第一行会出现异常,因为第一行变为String s = (String) getItemExtra(...);。
这就是Java中已知的通用方法。 T in表示您通常指定的类型。然后,编译器将用您替换它的类型替换T的任何实例。如果不这样做,编译器将尝试从可用信息中推断出正确的类型。
您应该查看Java Generics Tutorial以获得更深入的解释。
T是所谓的类型接口。在这个例子中,返回类型是一个类型接口,所以简单地说getItemExtra(...)将返回String或Uri足以让编译器知道此方法将返回该对象。话虽这么说,这不是引入类型接口的最好例子,所以这里是一个更简单的例子。
ArrayList是使用类型接口实现的,除了你告诉ArrayList它将包含哪个对象类型,除了T它??们使用的是E,这很好,因为只要你使用相同的字符是任意的整个实施中的角色。
以下是实际实现的相关摘录:
1 2 3
| public class ArrayList <E > extends AbstractList <E >
implements List <E >, RandomAccess, Cloneable, java. io. Serializable
{ |
因此,如果声明ArrayList,编译器将在编译时将E替换为String。同样适用于ArrayList,它将在整个实现过程中用YourCustomObject替换E。
-
我的问题是关于泛型方法,而不是泛型类。
-
它是一样的,你在构造函数中指定的那个,在调用方法时指定的另一个。