关于java:什么是泛型方法,在这种情况下如何绑定< T >?

What is a generic method and how is bound in this case?

本问题已经有最佳答案,请猛点这里访问。

前言:我理解泛型以及它们是如何在类级别声明的(例如class MyClass< T >)但我从未在静态方法的级别上声明它,并且没有任何显式绑定(例如class MySubclass extends MyClass)。

我在我正在处理的应用程序中找到了这段代码片段(我没有写这部分)。 我从未见过以这种方式声明的方法。 < T >未在班级中的任何其他位置定义。 Intent.getExtras().get()返回Object,实际上可能是StringBoolean ......等。

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 >使用什么类型? (是的,此方法编译并成功执行)。


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时,它将生成一个未经检查的强制转换警告,告诉您它无法检查您的类型转换是否合法,并且您可能会遇到类似这样的问题。


这就是Java中已知的通用方法。 T in表示您通常指定的类型。然后,编译器将用您替换它的类型替换T的任何实例。如果不这样做,编译器将尝试从可用信息中推断出正确的类型。

您应该查看Java Generics Tutorial以获得更深入的解释。


T是所谓的类型接口。在这个例子中,返回类型是一个类型接口,所以简单地说getItemExtra(...)将返回StringUri足以让编译器知道此方法将返回该对象。话虽这么说,这不是引入类型接口的最好例子,所以这里是一个更简单的例子。

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