簡體   English   中英

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

[英]JAVA: Methods that have same names?

在Main方法中,我調用了foo(1),並顯示“ foo a”。 所以我不明白為什么編譯器沒有給我一個錯誤,因為這兩個方法具有相同的名稱。

我還嘗試將它們設置為私有和公共,但仍然可以使用。

然后,當我將“ foo b”方法放在“ foo a”上方時,它將顯示“ foo b”。 那么編譯器是否按順序搜索方法?

這是所有代碼,

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

}

我無法編譯它。

我認為這可能與Java如何區分具有相同名稱/簽名的多種方法類似

您是從某處復制粘貼方法,還是在其中鍵入內容?

也許這也是先前編譯工作的結果。 您是否嘗試過清理項目(/刪除可執行文件),然后重新編譯/運行?

注:該代碼不能正常編譯。 您需要忽略 Eclipse上的錯誤才能進行編譯。

嗯,確實有效! 我現在認為這一定是個蝕怪,因為我仍然無法使用javac進行編譯。 使用eclipse強制編譯時,必須將第一個視為有效。 第二個引發編譯器錯誤,隨后Eclipse會忽略該錯誤。 因此,您始終打印鏈中第一個方法的結果。

日食

按照Narendra Pathai的建議,在已編譯的.class文件上運行javap確實只顯示了一種foo方法:) [是,我添加了-private標志]。

(結果):從“ Practice.java”編譯

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

(如果您交換了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);
}

編譯時錯誤-方法重復

不可能有重復的方法。 甚至月食也會出錯。

在此處輸入圖片說明

關於為什么它仍然可以運行的答案:

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

    at Main.main(Main.java:4)

我無法運行此代碼(我假設它們在同一個類中),它將引發錯誤“方法已定義....”,我認為這是正確的,因為這兩個方法都具有相同的名稱和參數,因此重載不會在這里申請。 我不認為改變公共和私人可以改變這種行為。 您確定可以正確運行此代碼嗎?

文檔

您不能聲明多個具有相同名稱,相同數量和類型的參數的方法,因為編譯器無法區分它們。

無論您聲明什么,此代碼都不會編譯。 再檢查一遍!

來自JLS( §8.4.2 )的補充(對於roliu ):

如果滿足以下任一條件,則方法m1的簽名是方法m2的簽名的子簽名:

m2與m1具有相同的簽名,或者

m1的簽名與m2的簽名的擦除(第4.6節)相同。

如果m1是m2的子簽名或m2是m1的子簽名,則兩個方法簽名m1和m2是等效的。

在類中聲明兩個具有重寫等效簽名的方法是編譯時錯誤。

由於這兩個方法foo()具有相同的簽名,因此它們是override-equivalent ,這意味着,根據規范,我們應該得到一個編譯錯誤。

更新:
JDK版本中有一個錯誤 :5.0和6u21已修復-但是,如果OP具有較舊版本的JDK,則可能會解釋該問題。

從JLS- 如果兩個方法具有相同的名稱和參數類型則它們具有相同的簽名; 確定的參數類型如下:

  • 它們具有相同數量的形式參數
  • 它們具有相同數量的類型參數

具有兩個“覆蓋等效”的方法是編譯錯誤。 也就是說,如果方法的形式參數具有相同的擦除,則它們是等效的。

根據我對JLS的閱讀, 可見性修飾符和/或static變量未計入方法簽名。 因此,此代碼無法在我的機器上進行編譯(Java 1.7.0_45)。


用外行的話來說:就像有人要你打開門一樣。

除此以外,您面前有兩扇門。 完全相同的門。

它們都是完全相同的顏色,紋理,形狀,並且具有相同的門把手。

他們甚至有相同的凹痕,叮當和划痕。

他們要您打開扇門? 沒有什么可以告訴他們的,甚至可以開始猜測哪一個是有效的。

這就是類型擦除的問題-如果您的方法具有相同的類型擦除 ,並且最終被覆蓋等效,那么Java也將面臨兩扇門的問題。 除了要猜測之外,它只是放下並要求您澄清。

我可以復制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);
    }

}

出:foo a

更多信息

 {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}

但是我發現這很奇怪,語言規范沒有說明具有不同訪問修飾符的重復方法。

我的IDE(日食)在方法上用紅色下划線抱怨,警告我有關重復的方法,但是代碼可以編譯並正常運行。

我只是在這里瀏覽了Java 7規范: http//docs.oracle.com/javase/specs/,並且(隱式)描述的代碼違反了該規范。

以下是相關片段:

8.4方法聲明

方法聲明可調用的可執行代碼,並傳遞固定數量的值作為參數。

MethodDeclaration:MethodHeader MethodBody

MethodHeader:MethodModifiers_opt TypeParameters_opt結果MethodDeclarator Throws_opt

MethodDeclarator:標識符(FormalParameterList_opt)

...

MethodDeclarator中的Identifier可以使用名稱來引用該方法。

類的主體將兩個具有重寫等效簽名的方法聲明為成員是一個編譯時錯誤(第8.4.2節)。

8.4.1形式參數

方法或構造函數的形式參數(如果有)由逗號分隔的參數說明符列表指定。

8.4.4通用方法

如果一個方法聲明了一個或多個類型變量(第4.4節),則該方法是通用的。這些類型變量稱為方法的類型參數。

8.4.2方法簽名

如果兩個方法的名稱和參數類型相同,則它們具有相同的簽名;如果滿足以下所有條件,則兩個方法或構造函數聲明M和N的參數類型都相同:

•它們具有相同數量的形式參數(可能為零)

•它們具有相同數量的類型參數(可能為零)

•令A1,...,An為M的類型參數,令B1,...,Bn為N的類型參數。將N型中Bi的每次出現重命名為Ai之后,相應類型變量的范圍相同,並且M和N的形式參數類型相同。

如果滿足以下任一條件,則方法m1的簽名是方法m2的簽名的子簽名:

•m2與m1具有相同的簽名,或

•m1的簽名與m2的簽名的擦除(第4.6節)相同。

如果m1是m2的子簽名或m2是m1的子簽名,則兩個方法簽名m1和m2是等效的。

在類中聲明兩個具有重寫等效簽名的方法是編譯時錯誤。

它定義方法名稱的方式對我來說有點模棱兩可,但我認為這很清楚,唯一引起簽名沖突的是:

  1. 方法名稱
  2. 通用類型參數(如果有)
  3. 輸入參數

它也不能 Eclipse 之外進行編譯。

從命令提示符運行javac (1.7):

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

在這里,定義什么是相同的方法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.

所以你會得到一個編譯時錯誤,那就是:檢查你的代碼和IDE

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

或者也許您正在運行以前的編譯類文件

這是由於公共/私有設置。 私有方法不能在obj ..之外訪問,但是公共方法可以,那不是錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM