"<T> T get()"是什么意思?(它有用吗?)

17

这似乎是有效的Java语法:

<T> T get();

但是这意味着什么?它有用吗?


给投票者的澄清说明

我了解当方法参数中使用T时所表示的含义,例如:

T get(Class<T> clazz);

返回类型可以从传入的类中推断出来。

但是当你没有参数来说明类型T是什么时,它是什么类型?


3
无论调用者要求什么,它就是什么,这意味着它可能是a) 总是抛出异常,b) 总是返回空值,c) 这是一个邪恶的黑客技巧。 - Louis Wasserman
2
@LouisWasserman为什么这是一个邪恶的黑客?正如Tom所指出的,它非常有用,可以在Guava中删除样板文件。 - beirtipol
2
@beirtipol "<T> ArrayList<T> newArrayList()" 和 "<T> T get()" 之间有区别。(尽管自 Java7 开始,第一个不再是必需的。) - Louis Wasserman
@aetheria 即使在那种情况下,你也应该明确地进行转换。 - Louis Wasserman
抱歉,这开始变成一次延长的对话了,但为什么呢?难道不是为了增加额外的代码而牺牲类型安全吗? - ᴇʟᴇvᴀтᴇ
显示剩余6条评论
3个回答

8

这是你将返回值赋给的变量类型。

例如,如果你有这样一个方法:

public static <T> T getGenericNumber() {
    // the number-generator might return int, double, float etc. values
    return (T) numberGenerator.getANumber();
}

例如,您可以直接将该方法的返回值分配给一个双精度值 - 无需转换:
Double a = getGenericNumber();

所以你基本上把变量的声明从方法中移动了出来。

这可能是危险的,因为你可以很容易地产生强制类型转换异常,例如你可以这样做 - 而仍然能够编译:

String s = getGenericNumber();

2
嗯,如果你已经将其明确绑定到“extends Number”,我认为你不能执行String s = getGenericNumber()。但我理解你的意思。 - ᴇʟᴇvᴀтᴇ
没错,你说得对 - 在这种情况下,你可以将其直接赋值给数字 - 我要修改它。 - Kristian Ferkić
所以你基本上是将类型转换从变量声明中移动到了方法中。这真的很明确。 - Satyam Raj

6

但是这意味着什么?

这意味着该语言具有一组旨在尽可能简单的规则,并且它们已经以一种不太实用的方式组合在一起。

泛型方法具有类型参数。类型参数可以在返回类型,参数列表和方法体中使用。它可以在其中任何一种组合中使用,包括完全不使用。

例如,这些签名都可以很有用:

<T> T foo( T t )  // The return type can be the type parameter
<T> List<T> ( )   // A type parameter does not have to be an argument
<T> T get()的情况使用相同的规则,但以不同方式组合。

这有用吗?

并不特别有用。您还没有展示实现方法。@LouisWasserman在一个深刻的评论中指出,实现要么会抛出异常,要么返回null,要么是一个hack。
以下是一个示例hack。我认为它并不实用,因为有一种更简单的方法来完成这个任务。也许如果你正在从C转换到Java,并希望代码尽可能平行,它可能会有用。
public static class Union {
    public Object o;
    public Union( Object value ) { o = value; }
    public Class<? extends Object> getType() { return o.getClass(); }
    public <T> T value() {
        return (T) o;   // <-- uses type parameter to cast
    }
}

public static void main(String[] args) {
    Union union = new Union( "foo" );

    Class<?> valueType = union.getType();
    if ( valueType.equals( String.class )) {
        String s = union.value();     // <-- the call 
        System.out.println( s );
    }
}

2

实际上它什么都不表示。下面的代码将编译,但会带有警告,并且最终会出错。没有必要在某些时候不声明/推断类型的情况下键入该方法。

public class GenericExample {
    public static void main(String[] args) {
        String eejits = get();
        System.out.println(eejits);

        Integer knobends = get(); // Throws a ClassCastException.
    }

    private static <T> T get() {
        return (T) "I love to downvote without explaining why";
    }
}

更明确地说,这并不比这样做更好(也许你只需要在一个地方进行强制转换)。

public class GenericExample {
    public static void main(String[] args) {
        String s = (String) get();
        System.out.println(s);

        Integer i = (Integer) get();
    }

    private static Object get() {
        return "I really hope the caller expects a String, cos otherwise I'm going to downvote them";
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接