12

I've been examining the Java Language Specification here (instead I should be out having a beer) and I am curious about what a method can contain. The specification states a method body can contain a block

MethodBody:
    Block

Where a 'Block' contains 'BlockStatements'. The 'BlockStatement' rule looks like this:

BlockStatement : 
    LocalVariableDeclarationStatement
    ClassOrInterfaceDeclaration
    [Identifier :] Statement

I can understand the 'LocalVariableDeclarationStatement' which could be

[final] int x, y, z;

However, I don't get why the 'ClassOrInterfaceDeclaration' rule is there. This rule looks like:

ClassOrInterfaceDeclaration: 
    ModifiersOpt (ClassDeclaration | InterfaceDeclaration)

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

InterfaceDeclaration: 
    interface Identifier [extends TypeList] InterfaceBody

What's going on here - You can't declare a class or interface within a block surely? Can someone help elucidate this confusion please?

Update: I can define a class within a method, but the following won't work:

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

The compiler complains stating "The member interface dooJa can only be defined inside a top-level class or interface"... any explanations?

Joeblackdev
  • 7,217
  • 24
  • 69
  • 106

5 Answers5

6

Oh yes you can declare a class inside a method body. :-)

class A {

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

}
Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
  • Well I'll be... I was thinking some sort of anonymous inner class or something. Thanks for that. – Joeblackdev Jul 09 '11 at 20:19
  • By the way - I thought I was being proactive by trying this out in Eclipse. However it gave me an error as I used the 'public' identifier, which isn't allowed (only abstract or final) but I got the error and just assumed (without checking) that you couldn't define a class or interface in a method. – Joeblackdev Jul 09 '11 at 20:23
  • Defining an interface within a method won't work for me though. In Eclipse I get an error stating: "The member interface dooJa can only be defined inside a top-level class or interface". Defining a class does work however. – Joeblackdev Jul 09 '11 at 20:36
  • Well, you could always use an anonymous inner class to create an instance of the interface within the enclosing method, no? – Joeblackdev Jul 09 '11 at 20:58
  • 1
    But you won't be able to return it (unless you plan on returning an Object) since the outside world doesn't know about the interface. Also, what's the point in enforcing a contract which is method scoped? :) – Sanjay T. Sharma Jul 09 '11 at 21:02
4

You've made a good observation about interfaces not working anymore. The reason is you that are looking at a very old version of the grammar. It looks to be over 10 year old. Take a look the grammar for Java 6 (what you are probably testing with):

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

You will see blockstatement:

BlockStatement: LocalVariableDeclarationStatement ClassDeclaration Statement

Dave L.
  • 9,595
  • 7
  • 43
  • 69
  • 2
    That's much better! Thank you for that. Now, where's that beer :-) – Joeblackdev Jul 09 '11 at 20:57
  • No problem. To be more precise here is the page that describes the different additions of the language spec: http://java.sun.com/docs/books/jls/index.html – Dave L. Jul 09 '11 at 21:00
1

An example for a block with an inner class declaration:

public class Test {

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

Although I doubt you'll find a use case...

emboss
  • 38,880
  • 7
  • 101
  • 108
1

As others have said, you can declare a class inside a method. One use case of this is to use this as an alternative for an anonymous inner class. Anonymous inner classes have some disadvantages; for example, you can't declare a constructor in an anonymous inner class. With a class declared locally in a method, you can.

Here's a silly example that doesn't really show why you'd want to do this, but at least how you could do it.

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);
}
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • True that, but the same doesn't seem to apply for an interface even thought the language specification says you can define an interface also. – Joeblackdev Jul 09 '11 at 20:56
1

These are called local classes. I use it occasionally, but it's not really a necessity.

Edit: a local class can be static, if it appears in a static context, for example, within a static method.

From the wording of the spec, local/inner/anno classe always means class only, not interface.

irreputable
  • 44,725
  • 9
  • 65
  • 93