您可以使用泛型进行方法重载并且只更改方法签名的泛型类型吗?

Posted

技术标签:

【中文标题】您可以使用泛型进行方法重载并且只更改方法签名的泛型类型吗?【英文标题】:Can you do method overloading with generics and only change the generic type of the method signature? 【发布时间】:2011-11-05 17:59:33 【问题描述】:

如果您不使用 Java 泛型,我相信在同一个类中不可能有两个仅在返回类型上有所不同的方法。

换句话说,这将是非法

public HappyEmotion foo(T emotion) 
    // do something
   

public SadEmotion foo(T emotion) 
    // do something else
   

在重载返回可能实现不同接口的泛型类型的方法时也是如此,例如如果以下两个方法存在于同一个类定义中:

public <T extends Happy> T foo(T emotion) 
    // do something
   

public <T extends Sad> T foo(T emotion) 
    // do something else
   

这是否违法?

【问题讨论】:

你试过编译吗? (符合标准的)编译器会立即告诉您什么是合法的,什么是非法的。一个更好的问题是“为什么......非法?”如果你不明白原因。 【参考方案1】:

这是合法的,因为输入参数也因类型而异..

因此,以下是合法的,

public <T extends Happy> T foo(T emotion) 
    // do something
   

public <T extends Sad> T foo(T emotion) 
    // do something else

但跟随不是,

public <T extends Happy> String foo(T emotion) 
    // do something
   

public <T extends Happy> T foo(T emotion) 
    // do something else
 

谢谢...

【讨论】:

【参考方案2】:

这运行得很好。

public class Main 
    public static void main(String[] args)
        Main main = new Main();
        main.foo("hello");
        main.foo(new Integer(5));
    

    public <T extends String> T foo(T emotion) 
        return (T) "test";
    

    public <T extends Integer> T foo(T emotion) 
        Integer integer = 5;
        return (T) integer;
     

【讨论】:

【参考方案3】:

它会编译,但问题在于 Happy 或 Sad 是否是另一个的超类。

例如,以下编译:

public <T extends Number> T sayHi() 
    System.out.println("number");
    return null;


public <T extends Integer> T sayHi() 
    System.out.println("integer");
    return null;

但是,当您尝试编译以下内容时会遇到问题:

Integer test = sayHi();

在这种情况下,您根本无法将&lt;Integer&gt; 添加到前面,因为 Integer 仍然是 Number 和 Integer。

但是以下编译

Double test2 = <Double>sayHi();

所以基本上只要 Sad 对象不能是 Happy 对象的实例,反之亦然,只要您在方法名称前使用 or 调用它,您的代码就应该可以工作。

【讨论】:

你怎么能写两个方法签名相同但返回类型不同的方法并说它可以编译,这完全违反了方法重载的概念【参考方案4】:

您可以使用泛型来区分Java中的方法。 JVM 看不到这种类型,但只要参数或返回类型不同,它仍将在 Sun/Oracle 编译器中编译。这不适用于 IBM/eclipse 编译器。

这表明您希望发生在字节码级别。 http://vanillajava.blogspot.com/2011/02/with-generics-return-type-is-part-of.html

【讨论】:

【参考方案5】:

正如其他人所说,这是合法的。但是,我想指出当类型相互扩展时会发生什么。

假设我们有两个接口(也适用于类,只需更改签名):

interface Emotion 
interface Happy extends Emotion 

还有两个功能:

<T extends Emotion> void foo(T obj)  // Referred as foo1
<T extends Happy> void foo(T obj)  // Referred as foo2

如果一个对象符合 Emotion,JVM 将选择 foo1。 如果一个对象符合 Happy,JVM 将选择 foo2 而不是 foo1。 注意优先顺序。这就是 JVM 解决歧义的方式。但是,这仅在您将泛型参数作为参数传递时才有效。

【讨论】:

以上是关于您可以使用泛型进行方法重载并且只更改方法签名的泛型类型吗?的主要内容,如果未能解决你的问题,请参考以下文章

c#泛型方法重载

Java的泛型方法概念原则

Maven打包泛型相关错误,找不到对应的签名方法

C#中的泛型是啥意思?

Swift 中的泛型 - “无法推断出泛型参数‘T’

对泛型类型调用重载方法'equals'