Является ли main действительным идентификатором Java?

288

Один из моих детей учится на Java в старшей школе, и у него было одно из его испытаний:

Что из следующего является допустимым идентификатором в Java?

а. 123java
б. main
с. java1234
д. {abce
е. )whoot

Он ответил б и ошибся.

Я посмотрел на этот вопрос и утверждал , что main является допустимым идентификатором , и что он должен был прав.

Мы взглянули на спецификацию Java для идентификаторов, и она подтвердила эту точку зрения. Мы также написали пример программы, в которой была названа переменная mainи метод. Он создал письменное опровержение, включающее ссылку на документацию по Java, тестовую программу, и учитель проигнорировал ее и сказал, что ответ по-прежнему неверен.

Является mainдействительным идентификатором?

Гари Бак
источник
12
Мне всегда грустно видеть учителя, настолько неуверенного, что он / она боится учиться чему-то новому и допускает ошибку.
Райан Ланди
Я думаю, это так. но вам действительно не следует использовать его в качестве имени переменной / метода (несмотря на очевидный случай), поэтому, если учитель пытается подробно рассмотреть вопрос, особенно в этом случае, об именах методов, тогда я могу увидеть его / ее точка зрения.
Бхарал
3
Этот вопрос действительно задает вопрос, правильно ли учитель вашего сына выполняет свою работу? Я вижу два действительных идентификатора Java. Таким образом, ответ «б» и «с». Так что учитель прав. Или я что-то упустил? Как это может быть таким вопросом? Судя о человеке, который даже не является частью сообщества ...
Jschnasse
1
Это вопрос об учителях, а не о Java.
ACV
1
Еще один из тех случаев, когда "выдумали ваши собственные вопросы с подвохом"; учителя действительно должны хотя бы взглянуть на спецификацию языка, прежде чем пытаться написать экзаменационный вопрос, подобный этому.
JRH

Ответы:

253
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, но не ключевое слово или BooleanLiteral или NullLiteral

IdentifierChars:

    JavaLetter {JavaLetterOrDigit}

JavaLetter:

    любой символ Unicode, который является «буквой Java»

JavaLetterOrDigit:

    любой символ Unicode, который является «буквой или цифрой Java»

Последовательность символов mainсоответствует приведенному выше описанию и отсутствует в списке ключевых слов в разделе 3.9 .

(Последовательность символов java1234также является идентификатором по тем же причинам.)

rgettman
источник
25
@Clockwork Вопрос был сформулирован так, что правильный выбор мог быть только один. Однако оба варианта b и c удовлетворяли условию вопроса, не совместимому с подразумеваемым выбором. Это позволило ребенку ОП выбирать между тем, какой правильный ответ считал правильный учитель.
rgettman
@rgettman Я читаю « Что из следующего ... », что позволяет несколько раз выбирать, на что « b и c » будет правильным ответом.
TripeHound
6
@TripeHound "является допустимым идентификатором" является единственным и требует ровно 1 ответ. Сравните это с «действительными идентификаторами»
дай мне 411
2
Вы могли бы также сделать класс main;)
Питер Лоури
97

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), либо нулевой литерал (§3.10.7), либо возникает ошибка времени компиляции.

Это означает, что вы можете доказать, что это действительный идентификатор, либо:

  • искать его в списке ключевых слов Java (подсказка: вы не найдете его там!) или просто
  • используя его в качестве идентификатора и наблюдая, что не возникает ошибка времени компиляции.
Майк Накис
источник
1
Не могли бы вы процитировать и изложить это более явно?
ноль298
36
нет, потому что это целый раздел. Если учитель считает, что этот раздел делает какое-то исключение для «основного», именно учитель должен показать, где он так говорит.
Майк Накис
76

Как говорится в других ответах

mainявляется допустимым идентификатором Java , а также java1234.

Я предполагаю, что сбивает с толку тот факт, что main(String[])метод часто используется в качестве точки входа в JVM 1 . Однако это не означает, что сам токен mainне может быть использован как идентификатор 2 .

Спецификации говорят так, и следующие объявления также действительны:

  • Поле:

    private int main;
  • Локальная переменная:

    String main = "";
  • Метод:

    private void main() { ... }
  • Класс (хотя имя класса, начинающееся со строчной буквы, не рекомендуется):

    public class main { ... }
  • Пакет:

    package main;

1: Как отмечено в комментариях, сама спецификация JVM не требует какого-либо конкретного метода в качестве точки входа, но широко используемый javaинструмент часто использует такой метод в качестве точки входа.
2: я вообще избегал бы создания основного метода кроме main(String[]).

MC Emperor
источник
22
«Я предполагаю, что путаница связана с тем, что метод main (String []) используется в качестве точки входа для JVM». mainне является точкой входа для JVM. Это точка входа, которую javaинструмент использует для запуска приложений. Другие инструменты (например, контейнеры сервлетов) используют другие точки входа.
TJ Crowder
27
что еще более иронично, потому что даже в «точке входа-контекста» main УЖЕ является действительным идентификатором. Таким образом, даже случай, который вы могли бы
возразить, на
@TJCrowder Спасибо, я включил это в ответ.
MC Emperor
1
@Hobbamok Вы, кажется, смущены основными понятиями Java, что, вероятно, объясняет, почему вы учите этому в школе, а не практикуете - вот ответ, который приходит на ум
rath
4
javaИнструмент не требует main(String[])метода , если основной класс расширяет javafx.application.Application .
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
MichaelK
источник
5
Можно ли добавить другой static mainметод с другими параметрами?
jpmc26
6
@ jpmc26 Попробуйте и расскажите, как все прошло. :)
MichaelK
1
Ну , это много сети
MC Emperor
4
@MCEmperor Да, это мой главный аргумент в пользу моего ответа. ;)
MichaelK
3
Вы забыли добавить package main;!
Соломон Уко
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;
        }
    }
}
18107
источник
2
Мне это нравится. Попробуйте 'grep -o main main.java | wc -l '
Гэри Бак,
3
Этот код напоминает мне язык программирования "ook" ^^ Почти каждое слово в этом коде является "основным" ...
Флориан Бах,
public static void main(main...Main)( пропуская пробел ) не может работать, не так ли?
GeroldBroser восстанавливает Монику
3
Я чувствую, что подчеркивал это.
Росс Прессер
1
@GeroldBroser Это чище, но не является строго необходимым: пробелы между токенами во многих случаях являются необязательными, они требуются только в том случае, если в противном случае также была бы допустимой конкатенация двух последующих токенов.
MC Emperor
44

Как mainнельзя использовать в качестве идентификатора, в то время как он используется в качестве идентификатора для объявления «основного» метода?

Для такой классической идиомы:

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

main не является ключевым словом и, вероятно, никогда не будет ключевым словом в 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).
  • назвать наши переменные с _, $или любыми неожиданными / unmeaningful символов , которые идут против общих соглашений об именах (4).
davidxxx
источник
7
Просто чтобы заметить, это mainможет быть ключевое слово, которое можно использовать только в качестве имени для статического метода с соответствующей сигнатурой (или как угодно). Обратите внимание, что вызовы суперкласса используют superтаким образом, что он выглядит как идентификатор: super(foo);и super.foo, но superявляется ключевым словом (и до того, как были добавлены дженерики, это был единственный способ его использовать (что я помню)).
jaxad0127
@ jaxad0127 Интересный момент, но я не совсем согласен. На самом деле это не так и в будущем, вероятно, не может быть по причинам совместимости. Если вы определили mainключевое слово в новой версии Java, это означает, что любой код, который использует main в качестве имени метода (или любые имена членов), больше не будет компилироваться. Использование superin generics не имеет побочных эффектов в существующем коде, поскольку generics не существовало в настоящее время.
davidxxx
2
Я просто имел в виду, что это МОЖЕТ быть сделано в качестве ключевого слова. То, что он выглядит как идентификатор, не означает, что так должно быть.
jaxad0127
2
Я бы сказал, что mainэто все же лучший идентификатор, чем java1234. Использование его для «обычного» метода будет вводить в заблуждение, но у меня не будет проблем с именованием переменной main, если это на самом деле главное в моем методе. java1234просто ужасно, имена должны быть описательными ...
AJPerez
1
"О вопросе, является ли основной хороший идентификатор?" Это зависит. Я бы, наверное, не взглянул на переменную с именем, mainесли бы функция, на которую я смотрел, что-то делала с данными по водопроводу. Я бы бросил, если бы я когда-либо видел java1234в производственном коде (и молюсь, что не было 1233 других переменных с префиксом java).
jpmc26
40

Это действительный идентификатор? Да.

Это хороший идентификатор? Нет, если вы используете его для чего-то другого, кроме метода, который запускается при запуске JVM.

В списке есть еще один действительный идентификатор? Да.

В инструкциях по тестированию сказано, чтобы выбрать лучший ответ?

user1423956
источник
7
Согласовано - множественный выбор, подобный этому, касается выбора «наилучшего» правильного ответа, когда их несколько. Тем не менее, это не делает этот вопрос с несколькими вариантами ответов, и я думаю, что говорить об этом с учителем - это правильно.
тень
19
@Shadow Это курс программирования. Неоднозначность вопроса о том, что указано в формальной математической грамматике, недопустима. Если говорить строго против этого стандарта (что подразумевается под словом « действительный »), оба ответа одинаково верны. Я могу представить себе гораздо больше случаев, в которых mainдопустимый идентификатор может java1234быть выше, чем в случае. Рассмотрим, например, кодовую базу, работающую с данными по водоснабжению (водопровод).
jpmc26
5
С другой стороны, java1234 воняет на высокое небо как идентификатор.
Джошуа
4
«выбрать лучший ответ» не означает «выяснить, когда учитель не знает, о чем они говорят, и угадать неправильный ответ, о котором они думают». main - это не только допустимый идентификатор, это очень важный идентификатор, потому что у каждого Java-приложения есть метод main, а методы имеют имена с идентификаторами.
fluffysheap
2
Я нахожу этот ответ очень самоуверенным и хотел бы, чтобы я проголосовал за него не раз. Кажется, вы пытаетесь принять сторону любой ценой и не рассматриваете более широкую картину. mainявляется идеальным идентификатором за пределами узкой области простого Java-приложения. Это может быть имя поля в классе, представляющее заданное меню. Или <main>раздел документа в конструкторе HTML. java1234с другой стороны, это так же ужасно, как и идентификаторы.
toniedzwiedz
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);
    }
}
ililit
источник
7

Этот учитель допустил небольшую ошибку, предполагая, что main не является допустимым идентификатором, или просто неправильно формулирует вопрос. Возможно, он хотел сказать «хороший идентификатор».
Но игнорирование аргументов ваших сыновей и, таким образом, препятствование его научному подходу проверки соответствующей литературы (спецификации Java) и проведения эксперимента (написания примера программы) является полной противоположностью того, что должен делать учитель.

user82593
источник
1
Как отмечено в других ответах, mainгораздо чаще «хороший» идентификатор, чем java1234был бы. Так что даже там учитель не прав. ;)
jpmc26
5

Оба mainи java123являются действительными идентификаторами, main не является зарезервированным ключевым словом, поэтому его вполне приемлемо использовать, поскольку в ходе теста вы должны были получить хотя бы одно очко или пол-очка.

shavar
источник
5
  1. Должно быть одно слово. То есть пробелы не допускаются.

    Пример: mangoprice действителен, но цена манго недействительна.

  2. Должен начинаться с буквы (алфавита) или подчеркивания или символа $.

    Пример: цена, _price и $ цена являются действительными идентификаторами.

  3. Не должно быть ключевым словом Java, поскольку ключевое слово несет особое значение для компилятора.

    Пример: класс или пустота и т. Д.

  4. Не должен начинаться с цифры, но цифра может быть в середине или в конце.

    Пример: 5mangoescost недействителен, а mango5cost и mangocost5 действительны.

  5. Длина идентификатора в Java может составлять 65 535 символов, и все они являются значительными. Идентификаторы чувствительны к регистру. То есть и к манго, и к манго относятся по-разному. Может содержать все заглавные буквы или строчные буквы или смесь.

ИДЕНТИФИКАТОР : это имена классов, имена методов, имена переменных ...

Так как main не является зарезервированным словом и в соответствии с объяснением выше для определения идентификатора main является допустимым идентификатором, а также java1234. Остальные опции недопустимы из-за вышеприведенного пояснения.

subhashis
источник