简体   繁体   English

JAVA:具有相同名称的方法?

[英]JAVA: Methods that have same names?

in the Main method, I called foo(1), and it prints "foo a". 在Main方法中,我调用了foo(1),并显示“ foo a”。 So I don't understand why the compiler doesn't give me an error since these two methods have the same names. 所以我不明白为什么编译器没有给我一个错误,因为这两个方法具有相同的名称。

I also tried to set them both private and public, and still works the same.. 我还尝试将它们设置为私有和公共,但仍然可以使用。

And then when I put that "foo b" method above the "foo a", then it prints "foo b". 然后,当我将“ foo b”方法放在“ foo a”上方时,它将显示“ foo b”。 So does the compiler search for the method in order? 那么编译器是否按顺序搜索方法?

Here's all the code, 这是所有代码,

public class Practice{

  public static void main(String[] args) {
     foo(1);
  }


  private static void foo(int n){
    System.out.println("foo a");
  }

  public static void foo(int n){
    System.out.println("foo b");
  }

}

Hmm. I can't get this to compile. 我无法编译它。

I think it could be a similar issue to How does Java distinguish these multiple methods with the same name/signature? 我认为这可能与Java如何区分具有相同名称/签名的多种方法类似 .

Did you copy paste a method from somewhere, or did you type them in? 您是从某处复制粘贴方法,还是在其中键入内容?

Perhaps this is also a holdover from a previous compilation effort. 也许这也是先前编译工作的结果。 Did you try cleaning your project (/ deleting the executable), and then recompiling/running ? 您是否尝试过清理项目(/删除可执行文件),然后重新编译/运行?

Note: The code does not NORMALLY compile. 注:该代码不能正常编译。 You need to ignore errors on eclipse to get it to compile. 您需要忽略 Eclipse上的错误才能进行编译。

Hmm it really works! 嗯,确实有效! I think now that it must be an eclipse quirk, since I still can't get it to compile using javac. 我现在认为这一定是个蚀怪,因为我仍然无法使用javac进行编译。 When you force compilation using eclipse, it must take the first one as valid. 使用eclipse强制编译时,必须将第一个视为有效。 The second one throws a compiler error, which is subsequently ignored by eclipse. 第二个引发编译器错误,随后Eclipse会忽略该错误。 Therefore, you always print the result of the first method in the chain. 因此,您始终打印链中第一个方法的结果。

日食

Following the advice of Narendra Pathai and running javap on the compiled .class file does indeed show only one foo method :) [Yes, I added -private flag]. 按照Narendra Pathai的建议,在已编译的.class文件上运行javap确实只显示了一种foo方法:) [是,我添加了-private标志]。

(result): Compiled from "Practice.java" (结果):从“ Practice.java”编译

public class Practice extends java.lang.Object{
    public Practice();
    public static void main(java.lang.String[]);
    public static void foo(int);
}

(if you swap public-private): Compiled from "Practice.java" (如果您交换了public-private):从“ Practice.java”编译

public class Practice extends java.lang.Object{
    public Practice();
    public static void main(java.lang.String[]);
    private static void foo(int);
}

Compile time error - Duplicate methods 编译时错误-方法重复

It is not possible to have duplicate methods. 不可能有重复的方法。 Even eclipse gives error. 甚至月食也会出错。

在此处输入图片说明

On answer to why can it still run: 关于为什么它仍然可以运行的答案:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 

    at Main.main(Main.java:4)

I can not run this code (I am assuming they are in same class), it throws error "method already defined...." which I think is correct since both the method has same name and and same arguments so overloading doesn't apply here. 我无法运行此代码(我假设它们在同一个类中),它将引发错误“方法已定义....”,我认为这是正确的,因为这两个方法都具有相同的名称和参数,因此重载不会在这里申请。 I do not think changing public and private can change this behavior. 我不认为改变公共和私人可以改变这种行为。 Are you sure that you can run this code without error ? 您确定可以正确运行此代码吗?

From the docs : 文档

You cannot declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart. 您不能声明多个具有相同名称,相同数量和类型的参数的方法,因为编译器无法区分它们。

This code will not compile regardless what you claim. 无论您声明什么,此代码都不会编译。 Check again! 再检查一遍!

Addition (for roliu), from JLS( §8.4.2 ): 来自JLS( §8.4.2 )的补充(对于roliu ):

The signature of a method m1 is a subsignature of the signature of a method m2 if either: 如果满足以下任一条件,则方法m1的签名是方法m2的签名的子签名:

m2 has the same signature as m1, or m2与m1具有相同的签名,或者

the signature of m1 is the same as the erasure (§4.6) of the signature of m2. m1的签名与m2的签名的擦除(第4.6节)相同。

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1. 如果m1是m2的子签名或m2是m1的子签名,则两个方法签名m1和m2是等效的。

It is a compile-time error to declare two methods with override-equivalent signatures in a class. 在类中声明两个具有重写等效签名的方法是编译时错误。

Since both methods foo() has the same signature they are override-equivalent which means that, according to the spec, we should get a compilation error. 由于这两个方法foo()具有相同的签名,因此它们是override-equivalent ,这意味着,根据规范,我们应该得到一个编译错误。

UPDATE: 更新:
There was a bug in JDK versions: 5.0 and 6u21 which was fixed - but if the OP has an older version of JDK that might explain the issue. JDK版本中有一个错误 :5.0和6u21已修复-但是,如果OP具有较旧版本的JDK,则可能会解释该问题。

From the JLS - two methods have the same signature if they have the same name and argument types ; 从JLS- 如果两个方法具有相同的名称和参数类型则它们具有相同的签名; argument types being determined as follows: 确定的参数类型如下:

  • They have the same number of formal parameters 它们具有相同数量的形式参数
  • They have the same number of type parameters 它们具有相同数量的类型参数

It is a compilation error to have two methods that are "override-equivalent"; 具有两个“覆盖等效”的方法是编译错误。 that is, if the methods' formal parameters have the same erasure, then they are override-equivalent. 也就是说,如果方法的形式参数具有相同的擦除,则它们是等效的。

From what I'm reading of the JLS, visibility modifiers and/or static do not factor into the method signature. 根据我对JLS的阅读, 可见性修饰符和/或static变量未计入方法签名。 Hence, this code fails to compile on my box (Java 1.7.0_45). 因此,此代码无法在我的机器上进行编译(Java 1.7.0_45)。


To put it in layman's terms: think of it like someone asking you to open the door. 用外行的话来说:就像有人要你打开门一样。

Except, there are two doors in front of you. 除此以外,您面前有两扇门。 Perfectly identical doors. 完全相同的门。

Both of them are the exact same color, texture, shape, and have the same doorknob. 它们都是完全相同的颜色,纹理,形状,并且具有相同的门把手。

They even have the same dents, dings and scratches in them. 他们甚至有相同的凹痕,叮当和划痕。

Which door did they want you to open? 他们要您打开扇门? There's nothing telling them apart to even begin guessing which one would be valid. 没有什么可以告诉他们的,甚至可以开始猜测哪一个是有效的。

That's the issue with the type erasure - if your methods have the same type erasure , and are ultimately override-equivalent, then Java is also faced with the two doors problem. 这就是类型擦除的问题-如果您的方法具有相同的类型擦除 ,并且最终被覆盖等效,那么Java也将面临两扇门的问题。 Except, instead of making a guess at it, it just lays down and demands clarification from you. 除了要猜测之外,它只是放下并要求您澄清。

I can duplicate OPs problem 我可以复制OP问题

    public class TestDuplicate {
    private static void foo(int n) {
        System.out.println("foo a");
    }

    public static void foo(int n) {
        System.out.println("foo b");
    }

    public static void main(String[] args) {
        foo(1);
    }

}

out: foo a 出:foo a

More info 更多信息

 {java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Program Files\Java\jre7\bin, java.vm.version=23.7-b01, user.country.format=NO, java.vm.vendor=Oracle Corporation, java.vendor.url=http://java.oracle.com/, path.separator=;, java.vm.name=Java HotSpot(TM) 64-Bit Server VM, file.encoding.pkg=sun.io, user.country=US, user.script=, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=Service Pack 1, java.vm.specification.name=Java Virtual Machine Specification, user.dir=C:\Workspace\StackOverflow, java.runtime.version=1.7.0_17-b02, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files\Java\jre7\lib\endorsed, os.arch=amd64, java.io.tmpdir=C:\Users\Maki\AppData\Local\Temp\, line.separator=
, java.vm.specification.vendor=Oracle Corporation, user.variant=, os.name=Windows 7, sun.jnu.encoding=Cp1252, java.library.path=C:\Program Files\Java\jre7\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\AMD APP\bin\x86_64;C:\Program Files (x86)\AMD APP\bin\x86;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Program Files\MiKTeX 2.9\miktex\bin\x64\;C:\Program Files\Java\jdk1.7.0_17\bin;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;., java.specification.name=Java Platform API Specification, java.class.version=51.0, sun.management.compiler=HotSpot 64-Bit Tiered Compilers, os.version=6.1, user.home=C:\Users\Maki, user.timezone=, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=UTF-8, java.specification.version=1.7, java.class.path=C:\Workspace\StackOverflow\bin, user.name=Maki, java.vm.specification.version=1.7, sun.java.command=TestDuplicate, java.home=C:\Program Files\Java\jre7, sun.arch.data.model=64, user.language=en, java.specification.vendor=Oracle Corporation, user.language.format=no, awt.toolkit=sun.awt.windows.WToolkit, java.vm.info=mixed mode, java.version=1.7.0_17, java.ext.dirs=C:\Program Files\Java\jre7\lib\ext;C:\Windows\Sun\Java\lib\ext, sun.boot.class.path=C:\Program Files\Java\jre7\lib\resources.jar;C:\Program Files\Java\jre7\lib\rt.jar;C:\Program Files\Java\jre7\lib\sunrsasign.jar;C:\Program Files\Java\jre7\lib\jsse.jar;C:\Program Files\Java\jre7\lib\jce.jar;C:\Program Files\Java\jre7\lib\charsets.jar;C:\Program Files\Java\jre7\lib\jfr.jar;C:\Program Files\Java\jre7\classes, java.vendor=Oracle Corporation, file.separator=\, java.vendor.url.bug=http://bugreport.sun.com/bugreport/, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=windows, sun.cpu.isalist=amd64}

I find it odd though, the language specs says nothing about duplicate methods with different access modifiers. 但是我发现这很奇怪,语言规范没有说明具有不同访问修饰符的重复方法。

My IDE (eclipse) complains with red underline on the methods warning me about duplicate methods but the code compiles and runs just fine. 我的IDE(日食)在方法上用红色下划线抱怨,警告我有关重复的方法,但是代码可以编译并正常运行。

I just skimmed the Java 7 spec here: http://docs.oracle.com/javase/specs/ and the code as (implicitly) described violates the spec. 我只是在这里浏览了Java 7规范: http//docs.oracle.com/javase/specs/,并且(隐式)描述的代码违反了该规范。

Here are the relevant snippets: 以下是相关片段:

8.4 Method Declarations 8.4方法声明

A method declares executable code that can be invoked, passing a fixed number of values as arguments. 方法声明可调用的可执行代码,并传递固定数量的值作为参数。

MethodDeclaration: MethodHeader MethodBody MethodDeclaration:MethodHeader MethodBody

MethodHeader: MethodModifiers_opt TypeParameters_opt Result MethodDeclarator Throws_opt MethodHeader:MethodModifiers_opt TypeParameters_opt结果MethodDeclarator Throws_opt

MethodDeclarator: Identifier ( FormalParameterList_opt ) MethodDeclarator:标识符(FormalParameterList_opt)

... ...

The Identifier in a MethodDeclarator may be used in a name to refer to the method. MethodDeclarator中的Identifier可以使用名称来引用该方法。

It is a compile-time error for the body of a class to declare as members two methods with override-equivalent signatures (§8.4.2). 类的主体将两个具有重写等效签名的方法声明为成员是一个编译时错误(第8.4.2节)。

8.4.1 Formal Parameters 8.4.1形式参数

The formal parameters of a method or constructor, if any, are specified by a list of comma-separated parameter specifiers. 方法或构造函数的形式参数(如果有)由逗号分隔的参数说明符列表指定。

8.4.4 Generic Methods 8.4.4通用方法

A method is generic if it declares one or more type variables (§4.4).These type variables are known as the type parameters of the method. 如果一个方法声明了一个或多个类型变量(第4.4节),则该方法是通用的。这些类型变量称为方法的类型参数。

8.4.2 Method Signature 8.4.2方法签名

Two methods have the same signature if they have the same name and argument types.Two method or constructor declarations M and N have the same argument types if all of the following conditions hold: 如果两个方法的名称和参数类型相同,则它们具有相同的签名;如果满足以下所有条件,则两个方法或构造函数声明M和N的参数类型都相同:

• They have the same number of formal parameters (possibly zero) •它们具有相同数量的形式参数(可能为零)

• They have the same number of type parameters (possibly zero) •它们具有相同数量的类型参数(可能为零)

• Let A1, ..., An be the type parameters of M and let B1, ..., Bn be the type parameters of N. After renaming each occurrence of a Bi in N's type to Ai, the bounds of corresponding type variables are the same, and the formal parameter types of M and N are the same. •令A1,...,An为M的类型参数,令B1,...,Bn为N的类型参数。将N型中Bi的每次出现重命名为Ai之后,相应类型变量的范围相同,并且M和N的形式参数类型相同。

The signature of a method m1 is a subsignature of the signature of a method m2 if either: 如果满足以下任一条件,则方法m1的签名是方法m2的签名的子签名:

• m2 has the same signature as m1, or •m2与m1具有相同的签名,或

• the signature of m1 is the same as the erasure (§4.6) of the signature of m2. •m1的签名与m2的签名的擦除(第4.6节)相同。

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1. 如果m1是m2的子签名或m2是m1的子签名,则两个方法签名m1和m2是等效的。

It is a compile-time error to declare two methods with override-equivalent signatures in a class. 在类中声明两个具有重写等效签名的方法是编译时错误。

The way it defines a method name is a bit ambiguous to me but I think it's clear, the only thing that matters for signature conflicts are: 它定义方法名称的方式对我来说有点模棱两可,但我认为这很清楚,唯一引起签名冲突的是:

  1. the method name 方法名称
  2. the generic type parameters, if any 通用类型参数(如果有)
  3. the input parameters 输入参数

It does not compile outside of Eclipse as well. 它也不能 Eclipse 之外进行编译。

Running javac (1.7) from the command prompt: 从命令提示符运行javac (1.7):

Practice.java:13: error: method foo(int) is already defined in class Practice
        public static void foo(int n){
                           ^
1 error

Here,define what's SAME method http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2 在这里,定义什么是相同的方法http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.2

two methods have the same signature if they have the same name and argument types.

So you would got a compile-time error ,that's to say :Check your code and IDE 所以你会得到一个编译时错误,那就是:检查你的代码和IDE

It is a compile-time error to declare two methods with override-equivalent signatures in a class.

Or maybe you are running your former compiled-class file 或者也许您正在运行以前的编译类文件

It is because of the public/private settings. 这是由于公共/私有设置。 The private method cannot be accessed outside of the obj.. however, the public one can and that's it is not an error. 私有方法不能在obj ..之外访问,但是公共方法可以,那不是错误。

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

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