Спецификация языка Java - не может понять «BlockStatement» - PullRequest
12 голосов
/ 10 июля 2011

Я изучал спецификацию языка Java здесь (вместо этого я должен выпить пива), и мне интересно, что может содержать метод. Спецификация заявляет, что тело метода может содержать блок

MethodBody:
    Block

Где «Блок» содержит «BlockStatements». Правило BlockStatement выглядит следующим образом:

BlockStatement : 
    LocalVariableDeclarationStatement
    ClassOrInterfaceDeclaration
    [Identifier :] Statement

Я могу понять 'LocalVariableDeclarationStatement', который может быть

[final] int x, y, z;

Однако я не понимаю , почему существует правило ClassOrInterfaceDeclaration. Это правило выглядит так:

ClassOrInterfaceDeclaration: 
    ModifiersOpt (ClassDeclaration | InterfaceDeclaration)

ClassDeclaration: 
    class Identifier [extends Type] [implements TypeList] ClassBody

InterfaceDeclaration: 
    interface Identifier [extends TypeList] InterfaceBody

Что здесь происходит - Вы не можете точно объявить класс или интерфейс внутри блока? Может кто-нибудь помочь объяснить эту путаницу, пожалуйста?

Обновление : я могу определить класс в методе, но следующее не будет работать:

public class Foo {
    public void doFoo() {
        interface dooJa {
            int bar();
        }
    }
}

Компилятор жалуется, заявляя, что "членский интерфейс dooJa может быть определен только внутри класса или интерфейса верхнего уровня" ... какие-либо объяснения?

Ответы [ 5 ]

6 голосов
/ 10 июля 2011

О, да, вы можете объявить класс внутри тела метода. : -)

class A {

    public void doIt() {
        class B {}
        B b = new B();
        System.out.println(b.getClass());
    }

}
4 голосов
/ 10 июля 2011

Вы хорошо заметили, что интерфейсы больше не работают. Причина в том, что вы смотрите на очень старую версию грамматики. Кажется, ему больше 10 лет. Взгляните на грамматику для Java 6 (что вы, вероятно, тестируете):

http://www.it.bton.ac.uk/staff/rnb/bosware/javaSyntax/rulesLinked.html#BlockStatement

Вы увидите blockstatement:

BlockStatement: LocalVariableDeclarationStatement ClassDeclaration Заявление

1 голос
/ 10 июля 2011

Это так называемые локальные классы. Я использую это время от времени, но на самом деле это не является необходимостью.

Редактировать: локальный класс может быть статическим, если он появляется в статическом контексте, например, в статическом методе.

Из формулировки спецификации, local / inner / anno classe всегда означает class, а не interface.

1 голос
/ 10 июля 2011

Как уже говорили другие, вы можете объявить класс внутри метода. Одним из вариантов использования этого является использование этого в качестве альтернативы для анонимного внутреннего класса. У анонимных внутренних классов есть некоторые недостатки; например, вы не можете объявить конструктор в анонимном внутреннем классе. С классом, объявленным локально в методе, вы можете.

Вот глупый пример, который на самом деле не показывает, почему вы хотите это сделать, но, по крайней мере, как вы можете это сделать.

public Runnable createTask(int a, int b) {
    // Method-local class with a constructor
    class Task implements Runnable {
        private int x, y;

        Task(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public void run() {
            System.out.println(x + y);
        }
    }

    return new Task(a, b);
}
1 голос
/ 10 июля 2011

Пример для блока с объявлением внутреннего класса:

public class Test {

    static 
    {
        class C {}
        C c = new C();
    }
}

Хотя я сомневаюсь, что вы найдете вариант использования ...

...