9

在 C++ 中,您可以在参数中指定函数的返回类型,例如:

C++

    float* myFloat = CollectionClass.ptr<float>();
    int*   myInt   = CollectionClass.ptr<int>();

Java中是否有等效的方法来指定返回类型而不添加额外的类参数?

爪哇

    //This doesn't work (due to type erasure) 
    public <T> T getDate() 
    {
        if (T instanceof Date)
            return new Date();
        if (T instanceof Calendar)
            return new Calendar();
    }

    Date myDate = getDate<Date>();
4

3 回答 3

19

用签名声明一个方法是完全可以的public <T> T getDate()

但是,不可能实现返回所需内容的方法。一个方法在运行时所做的不能仅仅依赖于它的类型参数,因为它不知道它的类型参数。

要对此有一个直觉,请意识到使用泛型编写的任何代码也可以在不使用泛型的情况下等效地编写,只需删除泛型参数并在适当的地方插入强制转换即可。这就是“类型擦除”的意思。

因此,要查看您的方法在泛型中是否可行,只需问一下,如果没有泛型,您将如何做:

public Object getDate() 
{
    // what would you do here?
}

Date myDate = (Date)getDate();

如果没有泛型就无法做到,那么使用泛型也无法做到。

C++ 模板完全不同。对于模板化函数和类,C++ 模板会为与它一起使用的每个类型参数生成函数或类的“单独副本”。即编译器采用模板化代码并将其“复制并粘贴”到多个版本中,每个版本都是单独的。因此,代码的每个副本都特定于某个类型参数,因此可以在运行时使用该类型。

这就是为什么要求 C++ 模板化代码以源代码形式提供以便您使用它的原因——没有“编译”模板之类的东西。但是,在 Java 中,可以使用已编译的泛型类。Java 中的泛型类和方法不对它们可以使用的类型做任何假设。

于 2013-02-27T20:09:52.260 回答
10

好的,现在进行编辑以明确代码以T...为条件

不,正如您的问题所提到的,由于类型擦除,Java 中没有什么简单的方法可以完成这项工作。你可以传入Class<T>

public <T> T getDate(Class<T> clazz)
{
    // Now use clazz to work out what to do
}

...但是您不能做任何取决于T执行时自身“价值”的事情,因为这根本不为人所知。不幸的是,泛型在 Java 中有些乏力:(


编辑:在编辑之前使代码以T...为条件

这只是以不同方式指定类型参数的问题:

import java.util.Date;

class Test {

    public static <T> T getDate() {
        return (T) new Date();
    }

    public <T> T getDateInstanceMethod() {
        return (T) new Date();
    }

    public static void main (String [] args) {
        Date date = Test.<Date>getDate();

        // Compiles fine, but is obviously bogus.
        String string = Test.<String>getDate();

        // And specifying a type argument for an instance method
        Test test = new Test();
        date = test.<Date>getDate();
    }
}

我也一直更喜欢“将类型参数放在常规参数之前”的方法,但是我们开始了......

编辑:正如 rgettman 指出的那样,类型推断在这里无论如何都会为您做正确的事情,因此在许多情况下您实际上不需要指定类型参数。有时你会这样做。

于 2013-02-27T17:25:07.090 回答
1

使用Arrays.asList,有时需要指定返回类型。Java 尝试根据所有参数的公共超类型“缩小”返回类型,但有时您需要特定类型。例如,

List<Number> list = Arrays.asList(1, 2, 3);

在这里,Arrays.asList返回 aList<Integer>并且你得到一个编译器错误。要让它返回 a List<Number>,您必须指定泛型类型。

List<Number> list = Arrays.<Number>asList(1, 2, 3);
于 2013-02-27T17:36:04.917 回答