2

in the Main method, I called foo(1), and it prints "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". 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");
  }

}
Lazy Frog
  • 59
  • 1
  • 7

10 Answers10

3

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?.

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.

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. When you force compilation using eclipse, it must take the first one as valid. The second one throws a compiler error, which is subsequently ignored by eclipse. Therefore, you always print the result of the first method in the chain.

eclipse

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].

(result): Compiled from "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 class Practice extends java.lang.Object{
    public Practice();
    public static void main(java.lang.String[]);
    private static void foo(int);
}
Community
  • 1
  • 1
3

Compile time error - Duplicate methods

It is not possible to have duplicate methods. Even eclipse gives error.

enter image description here

On answer to why can it still run:

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

    at Main.main(Main.java:4)
Narendra Pathai
  • 41,187
  • 18
  • 82
  • 120
2

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 ?

Ravi Kumar
  • 98
  • 6
2

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):

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

m2 has the same signature as m1, or

the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

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.

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.

Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • While the tutorial docs are certainly useful, I think it's always better to refer to the language specification when we are talking about the details of a language. It's easy to be mislead the reader when writing loosely in laymen's terms. In particular, here, it ignores the fact that the generic parameter types are also part of a method's signature. – rliu Nov 16 '13 at 04:58
  • @roliu - here you go ;) – Nir Alfasi Nov 16 '13 at 05:04
  • That's great and all but there were already two answers that referenced the JLS before yours (including mine :P). Also you don't explain what a method signature is. Anyways, it seems like the OP got what he wanted, though I can't really tell exactly what it is he wanted... – rliu Nov 16 '13 at 05:13
  • Not sure what you mean by another option. It seems pretty obvious to me that at least one of these things happened: 1) The OP is using some non-compliant compiler (which is what your bug suggests), 2) The compiler is being nice about this and the OP ignored compiler warnings, 3) The language spec has changed and some (very very very) old version of Java was much looser (perhaps unspecified) about method overload conflicts. Ultimately, since the OP isn't posting that information, we can't help. – rliu Nov 16 '13 at 05:23
  • @roliu I was referring to option #1 – Nir Alfasi Nov 16 '13 at 05:27
1

From the JLS - two methods have the same signature if they have the same name and argument types; 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. Hence, this code fails to compile on my box (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. Except, instead of making a guess at it, it just lays down and demands clarification from you.

Makoto
  • 104,088
  • 27
  • 192
  • 230
0

I can duplicate OPs problem

    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

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.

arynaq
  • 6,710
  • 9
  • 44
  • 74
  • 1
    Post the **entire** class that duplicates this behavior. – PM 77-1 Nov 16 '13 at 04:37
  • 1
    The language specs do say something about the return type being part of a methods descriptor and that no two methods can have the same description, which is odd consider the above... – arynaq Nov 16 '13 at 04:40
  • In order to run this code under Eclipse I had to click "Proceed" on a "Errors exist in required projecat(s)" dialog. I think once Eclipse has flagged the errors, and the programmer has chosen "Proceed" on that dialog, it is the programmer's choice to ignore the error. – Patricia Shanahan Nov 16 '13 at 04:42
  • True but I got no such thing, it had me surprised as well. – arynaq Nov 16 '13 at 04:45
  • 1
    It can't and won't compile under any version of Java I'm familiar with. For example: `javac -version` => javac 1.7.0_25; `javac TestDuplicate.java` => "TestDuplicate.java:6: error: method foo(int) is already defined in class TestDuplicate" – paulsm4 Nov 16 '13 at 04:53
0

I just skimmed the Java 7 spec here: http://docs.oracle.com/javase/specs/ and the code as (implicitly) described violates the spec.

Here are the relevant snippets:

8.4 Method Declarations

A method declares executable code that can be invoked, passing a fixed number of values as arguments.

MethodDeclaration: MethodHeader MethodBody

MethodHeader: MethodModifiers_opt TypeParameters_opt Result MethodDeclarator Throws_opt

MethodDeclarator: Identifier ( FormalParameterList_opt )

...

The Identifier in a MethodDeclarator may be used in a name to refer to the method.

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.1 Formal Parameters

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

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.

8.4.2 Method Signature

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:

• 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.

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

• m2 has the same signature as m1, or

• the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

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
rliu
  • 1,148
  • 6
  • 8
0

It does not compile outside of Eclipse as well.

Running javac (1.7) from the command prompt:

Practice.java:13: error: method foo(int) is already defined in class Practice
        public static void foo(int n){
                           ^
1 error
PM 77-1
  • 12,933
  • 21
  • 68
  • 111
0

Here,define what's SAME method 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

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

JessonChan
  • 216
  • 2
  • 3
-2

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.

DWolf
  • 703
  • 1
  • 7
  • 20
  • take the static out of it then.. All of the overloading methods i've seen on the web are all public void function.. – DWolf Nov 16 '13 at 04:29
  • @LazyFrog - The way you explain it, your code would not compile. Period. – PM 77-1 Nov 16 '13 at 04:35
  • -1 the method signature is neither defined by the access level modifiers nor by the fact if its static or not. – Nir Alfasi Nov 16 '13 at 05:20