主要是一个有效的Java标识符吗?

289

我的一个孩子在高中学习Java并在其中一次测试中遇到了这个问题:

以下哪个是Java中有效的标识符?

a. 123java
b. main
c. java1234
d. {abce
e. )whoot

他选择了 b ,但回答错误。

我看了看这道题,认为main是一个有效的标识符,并且应该正确。

我们查看了Java规范中有关标识符的内容,它也支持了这一点。我们还编写了一个名为main的变量和一个方法的示例程序。他撰写了一份书面反驳,其中包括了Java文档参考、测试程序,但老师忽略了这些,仍然认为答案是错误的。

main是一个有效的标识符吗?


20
看到一位教师太不自信,以至于害怕学习新事物和承认错误,总是让我感到悲伤。 - Ryan Lundy
我想是这样。但你真的不应该将其用作变量/方法名称(除非是显而易见的情况),所以如果老师试图强调要考虑周到,特别是在这种情况下,方法名称,那么我可以理解他/她的观点。 - bharal
3
这个问题是否真的在问,你儿子的老师是否做得很好?我看到两个有效的Java标识符。所以答案是 'b' 'c'。所以老师是正确的。或者我错过了什么?这怎么可能成为SO问题?评判一个甚至不是社区成员的人... - jschnasse
1
这是关于教师的问题,不是关于Java的问题。 - ACV
1
这又是一个“被自己的问题所欺骗”的案例;老师们在尝试编写这样的考试题之前,真的应该至少浏览一下语言规范。 - jrh
12个回答

254
public class J {
    public static void main(String[] args)
    {
        String main = "The character sequence \"main\" is an identifier, not a keyword or reserved word.";
        System.out.println(main);
    }
}

这个编译后,当执行时,会输出如下内容:

The character sequence "main" is an identifier, not a keyword or reserved word.

字符序列main是一个标识符,而不是关键字或保留字。JLS的相关部分为3.8:

标识符是Java字母和Java数字的无限长度序列,第一个字符必须是Java字母。

标识符:

    IdentifierChars但不是Keyword或BooleanLiteral或NullLiteral

IdentifierChars:

    JavaLetter {JavaLetterOrDigit}

JavaLetter:

    任何Unicode字符都是“Java letter”

JavaLetterOrDigit:

    任何Unicode字符都是“Java letter-or-digit”

字符序列main符合上述描述,并且不在第3.9节的关键字列表中。
(字符序列java1234也是一个标识符,原因相同。)

25
问题的措辞只能有一个选项是正确的。然而,选项B和C都符合问题的条件,与暗示的选择不一致。这让提问者的孩子需要选择哪个正确答案才是老师认为唯一正确的答案。请注意,我的翻译将尽力保持原文意思的准确性和简洁性。 - rgettman
@rgettman 我理解"以下哪个..."的意思是允许选择多个选项,因此"b和c"是一个有效的回答。 - TripeHound
7
“@TripeHound”是一个有效的标识符,是单数形式并需要准确回答1个。与“are valid identifiers”相比较,它是复数形式。 - Gimme the 411
2
你也可以把类命名为 main ;) - Peter Lawrey

98

main是Java中的一个有效标识符,老师错了。

相关文档在Java语言规范中,就在这里:

第3章“词法结构”,第3.8节“标识符”:

https://docs.oracle.com/javase/specs/jls/se10/html/jls-3.html#jls-3.8

文档中写道:

标识符是Java字母和Java数字的无限长序列,其中第一个必须是Java字母。标识符的拼写(Unicode字符序列)不能与关键字(§3.9)、布尔字面量(§3.10.3)或null字面量(§3.10.7)相同,否则会出现编译时错误。

这意味着,您可以通过以下方式证明它是有效的标识符:

  • 在Java关键字列表中查找它(提示:您在那里找不到它!);或者
  • 将其用作标识符并观察是否发生编译时错误。

1
你能更明确地引用并拼写出来吗? - zero298
36
不行,因为这是整个部分。如果老师认为这一部分对“main”有所特例,那么就需要老师指出在哪里有提到。 - Mike Nakis

80

正如其他答案所述,main是一个有效的Java标识符,java1234也是。

我猜混淆来自于JVM通常使用main(String[])方法作为入口点。但这并不意味着令牌main本身不能用作标识符。规范如此规定,并且以下声明也是有效的:

  • 一个字段:

    private int main;
    
  • 本地变量:

    String main = "";
    
  • 一种方法:

    void main() { ... }
    
  • 一个类或接口(虽然不鼓励以小写字母开头的类或接口名称):

  • class main { ... }
    
  • 一个包裹:

    package main;
    

1:正如评论中所述,JVM规范本身并没有指定任何特定的方法作为入口点,但广泛使用的java工具通常会使用这样的方法作为入口点。
2:我通常会避免创建除了main(String[])之外的主方法。


补充:我觉得这不是抱怨的地方,但这是我的正确的谦虚的意见:标识符mainjava1234一样有效,因此必须同等有效或错误。否则是不可容忍的。


23
“我猜混淆是因为main(String [])方法被用作JVM的入口点。” “main”不是JVM的入口点。它是“java”工具用于运行应用程序的入口点。其他工具(例如servlet容器)使用其他入口点。 - T.J. Crowder
27
更具讽刺意味的是,因为即使在“入口点上下文”的主函数中,"main"本身已经是一个有效的标识符。所以,即使你想反驳它,实际上也证明了问题的提出者是正确的。 - Hobbamok
@T.J.Crowder 谢谢,我已经在答案中包含了。 - MC Emperor
广告2:我通常会避免创建除了public static void main(String[])之外的主方法。 ;) - Gerold Broser
2
“@Hobbamok 你似乎对Java的基本概念感到困惑,这也许解释了为什么你在学校教授它而不是实践。” - rath
4
如果主类继承自javafx.application.Application,则java工具不需要main(String[])方法。 - VGR

65

这在Java 1.8上可以成功编译...

public class main {

    public String main = "main"; 

    public void main(String main) {
        System.out.println("This object is an instance of the class " + this.getClass().getCanonicalName());
        System.out.println("The value of the argument \"main\" for this call to the method \"main(String main)\" is " + main);
        System.out.println("The value of the field \"main\" is " + this.main);
    }

    public static void main(String[] args) {
        main main = new main();
        main.main(main.main + main.main);
    }
}

...并在执行时产生输出:

This object is an instance of the class main
The value of the argument "main" for this call to the method "main(String main)" is mainmain
The value of the field "main" is main

5
能否添加另一个具有不同参数的“static main”方法? - jpmc26
6
尝试一下并告诉我们效果如何。 :) - MichaelK
1
那真是很多的主函数。 - MC Emperor
5
@MCEmperor 是的,这是我回答的主要论点。;) - MichaelK
4
你忘记加上package main;了! - Solomon Ucko

45

我试了各种方法,看起来都能运行。我会说main是一个有效的标识符。

package main;

public class main {

    static main main;
    String Main;

    main(String main) {
        Main = main;
    }

    main(main main) {
        System.out.println(main.Main);
    }

    main main(main main) {
        return new main(main);
    }

    public static void main(main...Main) {
        main:
        for (main main : Main) {
            main = (main instanceof Main) ? new main(main): main.main(main);
            break main;
        }
    }

    public static void main(String[] args) {
        main = new main("main");
        main.main(main, main);
        main = main.new Main(main) {
            main main(main main) {
                return ((Main)main).main();
            }
        };
        main.main(main);
        main.main(main,main);
    }

    abstract class Main extends main {
        Main(main main) {
            super("main");
        }

        main main() {
            main.Main = "Main";
            return main;
        }
    }
}

2
我喜欢它。尝试一下 'grep -o main main.java | wc -l'。 - Gary Bak
3
这段代码让我想起了编程语言"ook" ^^ 这段代码中几乎每个单词都是"main" ... - Florian Bach
public static void main(main...Main)(缺少一个空格)不能工作,对吗? - Gerold Broser
3
我感觉就像是我静脉注射了它。 - Ross Presser
1
@GeroldBroser 这样更加简洁,但并非必须的:在许多情况下,标记之间的空格是可选的,只有当两个相邻标记的连接也有效时才需要它们。 - MC Emperor
循环标签加一分。我差点忘记它的存在。 - MC Emperor

44

如何在“main”被用于声明“main”方法的同时,又不能将其用作标识符?

对于这样一个经典的习语:

public class Foo{
   public static void main(String[] args){
   }
}

main不是Java中的关键字,出于明显的向后兼容性原因,它可能永远不会成为Java中的关键字。


关于问题,“main”是否是一个好的标识符?

首先:对编译器有效并不意味着一定好。
例如,建议使用的“java1234”选项也是有效的标识符,但应该尽量避免使用。

main具有非常特殊和重要的含义:它被用作类和JAR文件的入口点方法,由java命令行执行。
main用于不满足由java命令行使用的方法名称将会产生误导,而将其用作变量名或类名则有道理。
例如,将表示应用程序入口点的类定义为应用程序的Main类是可以接受的,因此将其用作变量名也是可以的,比如:

public class Main {

  public static void main(String args[]){
     Main main = new Main();
     // ...
  }      

}

一般来说,在Java中,多个字符或“单词”被视为编译器有效的标识符,但强烈建议不要在客户端代码中使用它们(但生成的代码可能会这样做:例如嵌套类),因为它们不易读或者真正具有误导性。

例如,以下内容对于编译器而言是合法的:

public class Object { // 1
    public void foo() {
       ...
    }
}

public class BadChosenIdentifier {

    public static void main() { // 2
        new BadChosenIdentifier().toString(new Object());  
    }

    public void toString(Object java1234) { // 3, 4
        String _result$ = java1234 + " -> to avoid"; // 4
        System.out.println(_result$);
    }    
}

但我们不想:

  • 将我们的类命名为Object,因为这在java.lang中已经被定义 (1)。
  • 命名一个方法为main(),如果它不符合被java命令行使用的标准 (2)。
  • 重载Object.toString()方法 (3)。
  • _$或任何违反共享命名约定的意外/无意义字符来命名变量 (4)。

7
需要注意的是,main 可能只能作为具有适当签名(或其他)的静态方法的名称使用的关键字。请注意,超类调用在使用 super 方式时看起来像标识符:super(foo);super.foo,但 super 是一个关键字(在泛型被添加之前,这是唯一可以使用它的方式(我能记得的))。 - jaxad0127
2
我只是想说它本来可以作为一个关键字。仅仅因为它看起来像标识符,并不意味着它必须是这样的。 - jaxad0127
@jaxad0127,不深入研究JLS,并针对您提到的两种情况,我认为可以说super是一个特殊表达式:它表示对Class对象的引用,可与对象的构造函数及其成员一起使用。 - Gerold Broser
2
我认为main仍然比java1234更好。将其用于“普通”方法会产生误导,但是如果它实际上是我的方法中的主要内容,我命名一个变量为main没有问题。java1234太糟糕了,名称应该是描述性的... - AJPerez
1
关于这个问题,“main”是一个好的标识符吗?这要看情况。如果我正在查看的函数与水管数据有关,那么我可能不会对名为“main”的变量感到惊讶。但如果我在生产代码中看到“java1234”,我会感到非常恶心(并祈祷没有其他以“java”为前缀的1233个变量)。 - jpmc26
显示剩余3条评论

40

这是一个有效的标识符吗?是的。

如果你不仅仅是用它来启动JVM方法,那么这个标识符还好吗?不好。

是否列出了另一个有效的标识符?是的。

测试说明中是否说要选择最佳答案?


7
同意-像这样的多项选择题是在存在多个选项的情况下选择最好的正确答案。但是,这并不意味着这是一个好的多项选择题,我认为与老师谈论这件事是正确的做法。 - Shadow
19
@Shadow这是一个编程课程。在涉及到使用正式数学语法进行明确定义的问题上存在歧义是不可接受的。从严格遵循这个标准(这也是“valid”所暗示的),两个答案都是正确的。例如,在处理供水数据(供水管道)的代码库中,我可以想象出更多情况下main是一个可以容忍的标识符,而java1234则只有很少的可能性。 - jpmc26
5
另一方面,作为标识符,java1234的质量极差。 - Joshua
4
“选择最佳答案”并不意味着“猜测老师正在想的错误答案”。 main不仅是一个有效的标识符,它还是一个非常重要的标识符,因为每个Java应用程序都有一个main方法,而方法是用标识符命名的。 - fluffysheap
2
我认为这个答案非常主观,我希望我可以多次踩它。看起来你试图不惜一切代价站在一边,而没有考虑更广泛的情况。main 在纯 Java 应用程序之外的任何地方都是一个完全合适的标识符。它可以是表示套餐菜单的类中字段的名称。或者是 HTML 构建器中文档的 <main> 部分。另一方面,java1234 是最糟糕的标识符之一。 - toniedzwiedz
显示剩余2条评论

29

29
public class Main {
    private static String main;
    public static void main(String[] main) {
        Main.main = main[0];
        new Main().main(Main.main);
    }
    private void main(String main) {
        System.out.println(main);
    }
}

7

那个老师犯了一个小错误,要么是假设 main 不是一个有效的标识符,要么是用词不当。他可能想说“一个好的标识符”。
但是忽略你儿子的论据,从而阻碍他通过检查相关文献(Java规范)和执行实验(编写样例程序)的科学方法,这恰恰与老师应该做的事情完全相反。


1
正如其他答案所指出的那样,“main”比“java1234”更常用且更为合适作为标识符。因此,即使在这种情况下,老师也是错误的。 ;) - jpmc26

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