两个Java方法能够使用相同的名称但返回类型不同吗?

97

两个Java方法的方法名相同,但返回类型不同,这种情况允许吗?这些方法的返回类型不同,并且使用相同的方法名声明。

是否允许这样做?


如果类相同,并且仅当两种方法具有不同的参数时才可能。 - Annu
10
@Aleadam - 这重要吗?原帖作者正在寻求信息...不是代码。 - Stephen C
@Stephen 是的,但很容易找到任何书的前几章中可以找到的信息,这就是我在问的原因。 - Aleadam
你是想说一样的签名还是只是方法名字?这会有很大的区别。 - Ravisha
1
@Aleadam - 我不明白你的推理。你是说如果这是作业,那么OP需要在书中查找答案吗?(而不是其他情况下?)如果不是,那么你提出问题的相关性是什么? - Stephen C
显示剩余2条评论
9个回答

95

如果两种方法具有相同的参数类型,但返回类型不同,则不可能。来自Java语言规范,Java SE 8版,§8.4.2. 方法签名

如果两个方法或构造函数M和N具有相同的名称、相同的类型参数(如果有)(§8.4.4),并且将N的形式参数类型调整为M的类型参数后,具有相同的形式参数类型,则它们具有相同的签名。

如果两种方法具有不同的参数类型(因此它们具有不同的签名),则是可能的。这被称为重载。


9
谢谢您对规范的链接,以及正确清晰的表述。+1 - Stephen C
但这有什么用处呢? - user3932000

37

只有当它们接受不同的参数时,才能使用相同的名称。如果没有参数,那么你必须使用不同的名称。

int doSomething(String s);
String doSomething(int); // this is fine


int doSomething(String s);
String doSomething(String s); // this is not

1
不仅如此,int doSomething(string)和String dosomething(String)具有不同的返回类型,因此在Java字节码中的签名也是不同的,因此是允许的。要调用这个方法,你必须使用反射或字节码。 - barwnikk
@barwnikk:当然,但返回类型与此无关-它们也有不同的名称,因为大小写不同。 - Kaivosukeltaja
1
大小写的区别是因为我的Shift键坏了。 ;) 你可以创建两个具有相同参数和方法名称但不同返回值的方法。但是在Eclipse中会出现问题。当你调用方法时,会出现错误,所以你必须使用字节码。 ;) 很多混淆器都使用这种方法。如果你知道字节码,类名可以是“if”、“do”、“for”。 - barwnikk

23
根据JLS,如果使用泛型,尽管Java 6/7编译器(Oracle的JDK,OpenJDK,IBM的JDK)存在特性/错误,你仍然不能在相同的方法签名中有不同的返回类型。
public class Main {
    public static void main(String... args) {
        Main.<Integer>print();
        Main.<Short>print();
        Main.<Byte>print();
        Main.<Void>print();
    }

    public static <T extends Integer> int print() {
        System.out.println("here - Integer");
        return 0;
    }
    public static <T extends Short> short print() {
        System.out.println("here - Short");
        return 0;
    }
    public static <T extends Byte> byte print() {
        System.out.println("here - Byte");
        return 0;
    }
    public static <T extends Void> void print() {
        System.out.println("here - Void");
    }
}

打印

here - Integer
here - Short
here - Byte
here - Void

想了解更多细节,请阅读我的这篇文章


3
JLS确实允许这4种方法,即使它们具有相同的返回类型。实际上,在讨论重载(#8.4.2)时根本不考虑返回类型。因此,按照当前的语言规范,允许这4种方法并不是一个错误。然而,如果它们具有相同的返回类型,javac无法编译它们-这是一个错误。这是语言规范的问题;他们没有非常仔细地思考整个泛型的事情。 - irreputable
@irreputable,关于泛型的问题我同意,这就是为什么如果延迟闭包意味着设计经过深思熟虑,那么我认为这可能是一件好事。 ;) 看看你必须做什么才能创建一个泛型数组,或者使用双重和三重转换,或者即使是java.util.ArrayList也不能编译而不带警告(这必须是最基本的用例)。 - Peter Lawrey

9

不允许在C++和Java中基于函数返回类型进行重载。原因是基于返回类型的重载可能会引起混淆(开发人员很难预测将调用哪个重载)。实际上,有些人认为任何形式的重载都可能会在这方面引起混淆,并建议避免使用,但即使是那些支持重载的人似乎也同意这种特定形式太令人困惑。


在Java中,至少有两个方法可以具有相同的名称和不同的返回类型,前提是它们还具有不同的参数类型;请参阅@uthark答案链接的JLS部分。 - Stephen C
2
没错,但这不是针对返回类型的重载,而是针对参数类型的重载。并且重载恰好具有不同的返回类型(返回类型与重载完全无关)。 - Michael Aaron Safyan

7

如果一个方法是继承来的,并且返回类型是兼容的,那么你可以使用相同参数但不同返回类型的两个方法。

例如:

public class A
{
    Object foo() { return null; }
}

public class B
    extends A
{
    String foo() { return null; }
}

2
没错,我今天早些时候才发现这个问题。如果你调用 B.class.getDeclaredMethods(),你会看到两个版本都出现了。你可以通过反射调用任意一个版本。 - Adam Burley

4

即使这是一个旧的线程,也许有些人会感兴趣。

如果您可以在同一类中使用相同的方法并存档不同的返回类型,则可以使用泛型: Oracle Lesson Generics

泛型值持有类的简单示例:

class GenericValue<T> {
  private T myValue;

  public GenericValue(T myValue) { this.myValue = myValue; }

  public T getVal() { return myValue; }
}

并像这样使用:

public class ExampleGenericValue {
  public static void main(String[] args) {
    GenericValue<Integer> intVal = new GenericValue<Integer>(10);
    GenericValue<String> strVal = new GenericValue<String>("go on ...");

    System.out.format("I: %d\nS: %s\n", intVal.getVal(), strVal.getVal());
  }
}

以下是这段代码的输出结果:
I: 10
S: go on ...

4

2

只有当它们的参数声明与内存不同才能生效。


1
如果它与具有相同类型和顺序的相等数量参数的同一类别在同一类中,则不可能,例如:
int methoda(String a,int b) {
        return b;
}
String methoda(String b,int c) {
        return b;    
}

如果参数数量和类型相同但顺序不同,则可能会导致方法重载。这意味着,如果方法签名相同,包括方法名称、参数数量及其类型以及它们定义的顺序。

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