简体   繁体   English

在Java中使用Generic返回类型调用方法

[英]Method call with Generic return type in Java

In C++ you can specify the return type of a function in a parameter, such as: 在C ++中,您可以在参数中指定函数的返回类型,例如:

C++ C ++

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

Is there an equivalent in Java to specify the return type without adding additional class args? Java中是否有等价物来指定返回类型而不添加额外的类args?

Java 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>();

It's perfectly fine to declare a method with the signature public <T> T getDate() . 使用签名public <T> T getDate()声明一个方法是完全正常的。

However, it is impossible to implement the method that returns what you want. 但是,无法实现返回所需内容的方法。 What a method does at runtime cannot depend on its type parameter alone, because it doesn't know its type parameter. 方法在运行时的作用不能仅依赖于它的类型参数,因为它不知道它的类型参数。

To get an intuition for this, realize that any code written with generics can also be written equivalently without using generics, by simply removing generic parameters and inserting casts where appropriate. 为了获得对此的直觉,请认识到使用泛型编写的任何代码也可以在不使用泛型的情况下等效编写,只需删除泛型参数并在适当的位置插入强制转换。 This is what "type erasure" means. 这就是“类型擦除”的含义。

Therefore, to see whether your method would be possible in Generics, simply ask, how would you do it without Generics: 因此,要想看看你的方法是否可以在泛型中使用,只需问一下,如果没有泛型,你会怎么做:

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

Date myDate = (Date)getDate();

If you can't do it without Generics, you cannot do it with Generics either. 如果没有Generics就无法做到,那么你也无法使用Generics。

C++ templates are completely different. C ++模板完全不同。 For templated functions and classes, C++ templates generate a ''separate copy'' of the function or class for each type argument that is used with it. 对于模板化函数和类,C ++模板为与其一起使用的每个类型参数生成函数或类的“单独副本”。 ie the compiler takes the templated code and "copy and pastes" it into multiple versions, each separate. 即编译器获取模板化代码并将其“复制并粘贴”到多个版本中,每个版本都是独立的。 Therefore, each copy of the code is specific to a certain type argument, and can thus use that type at runtime. 因此,代码的每个副本都特定于某个类型参数,因此可以在运行时使用该类型。

This is why C++ templated code is required to be available in source form in order for you to use it -- there is no such thing as "compiled" templates. 这就是为什么C ++模板化代码需要以源代码形式提供才能使用它 - 没有“编译”模板这样的东西。 However, in Java, a compiled generic class can be used. 但是,在Java中,可以使用编译的泛型类。 Generic classes and methods in Java do not assume anything about the types they can be used on. Java中的通用类和方法不会假设它们可以使用的类型。

Okay, now with the edit to make it clear that the code is conditional on T ... 好的,现在通过编辑清楚地表明代码是以T为条件的......

No, there's nothing simple within Java to make this work - due to type erasure, as your question mentions. 不,在Java中没有任何简单的方法可以实现这一功能 - 由于类型擦除,正如您的问题所提到的那样。 You can pass in Class<T> : 你可以传入Class<T>

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

... but you can't do anything which depends on the "value" of T itself at execution time, as that's simply not known. ...但是你不能做任何依赖于T本身在执行时的“价值”的事情 ,因为那是根本不知道的。 Generics is somewhat anaemic in Java, unfortunately :( 不幸的是,遗传学在Java中有些贫血:(


EDIT: Before the edit to make the code conditional on T ... 编辑:在编辑之前使代码以T为条件...

It's just a matter of specifying the type argument differently: 这只是以不同方式指定类型参数的问题:

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();
    }
}

I've always preferred the "put the type arguments just before the regular arguments" approach too, but there we go... 我总是更喜欢“在常规参数之前放置类型参数”的方法,但是我们去...

EDIT: As rgettman points out, type inference will do the right thing for you anyway here, so you don't actually need to specify the type arguments in many cases. 编辑:正如rgettman指出的那样,类型推断无论如何都会为你做正确的事情,因此在很多情况下你实际上并不需要指定类型参数。 Sometimes you do though. 有时你会这样做。

With Arrays.asList , sometimes it's necessary to specify the return type. 使用Arrays.asList ,有时需要指定返回类型。 Java attempts to "narrow" the return type based on the common supertype(s) of all the arguments, but sometimes you need a specific type. Java试图根据所有参数的常见超类来“缩小”返回类型,但有时您需要特定类型。 For example, 例如,

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

Here, Arrays.asList returns a List<Integer> and you get a compiler error. 这里, Arrays.asList返回List<Integer>并且您得到编译器错误。 To get it to return a List<Number> , you must specify the generic type. 要使其返回List<Number> ,必须指定泛型类型。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM