1

Please take a look at this snippet:

public class A {
    void method() {
        System.out.print(B.j);//This is legal!
        class C {
            void method () {
                System.out.print(j);//This is illegal!
            }
        }
        final int j = 10;
        class D {
            void method() {
                System.out.print(j);//This is legal!
            }
        }
    }
}
class B {
    static int j = 10;
}

We can access the 'B.j' in a place before it's definition whilst this is illegal in the case of accessing 'final int j' in class C.

Does java compiler looks at local classes as simple variables/objects? Specially, what's the rationale behind this behavior? I mean forward checking is working for the B.j but it doesn't work for the 'j' inside the class C.

Mohsen Kamrani
  • 7,177
  • 5
  • 42
  • 66

2 Answers2

5

I believe this is simple scoping. If you replace your inner classes with simple System.out.println() calls,

public class A {
  void method() {
    System.out.print(j);//This is illegal!
    final int j = 10;
    System.out.print(j);//This is legal!
  }
}

you'll find you get the same message. The scope of local variables starts where they are declared and continues through the end of the block they're declared in.

To answer your question about the reference to B: Consider

public class A {
  void method() {
    System.out.print(k);//This is legal!
  }
  int k=17;
}

Java is not a single-pass compilation. Classes, and their exposed fields and methods, can be forward referenced. A deliberate decision was made that local variables can not be forward referenced. I'm guessing that this was to let programmers establish restricted scopes without having to use additional levels of {} block statements -- if I introduce a new variable, especially with an initialization, I don't want anyone tampering with it before that.

That's how Java local variables happen to work. This may not be a satisfying answer, but it's the best one we've got.

keshlam
  • 7,931
  • 2
  • 19
  • 33
  • Of course you're right. Obviously this is all about scope. but why I can access to B.j? – Mohsen Kamrani Mar 01 '14 at 06:26
  • 1
    Because B.j is a static. It doesn't belong to any individual object or method or execution path; it belongs to class B. – keshlam Mar 01 '14 at 06:28
  • I just defined it static to avoid making an object, even if I remove the static keyword again it's legal(using an object of class B). – Mohsen Kamrani Mar 01 '14 at 06:35
  • Scoping of access to fields of other classes -- and, for that matter, scoping to fields of your own class -- is different from scoping of access to local variables. It didn't have to be that way, but that's the way Java is defined. I'm afraid you aren't going to get a better answer than that. – keshlam Mar 01 '14 at 06:39
  • 1
    I think this is the best explanation. It's quite hard to pinpoint the exact definition in the Java Language Specification, but I think the best place is section 4.12.3 sub 7: "Whenever the flow of control enters a block (§14.2) or for statement (§14.14), a new variable is created for each local variable declared in a local variable declaration statement immediately contained within that block or for statement." http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12 – Erwin Bolwidt Mar 01 '14 at 06:58
  • 1
    Hmm 4.12.3 doesn't explain why you can only reference a local variable after it is declared and not through the whole block. But section 6.3 does: "The scope of a local class declaration immediately enclosed by a block (§14.2) is the **rest of the immediately enclosing block**, including its own class declaration." – Erwin Bolwidt Mar 01 '14 at 07:03
0

Setting the possibility that your code does not compile aside...

When class A is loaded by the classloader into memory, so is class B, because they're in the same file. So B.j is already allocated on the heap when method is called at runtime.

On the other hand, when you declare variables in a method, those variables are stored on the stack when the method is invoked, in the order that you write them, so here order matters.

ktm5124
  • 11,861
  • 21
  • 74
  • 119
  • So do you mean compiler considers classes C and D as variables? – Mohsen Kamrani Mar 01 '14 at 06:27
  • The order of declaration matters inside a method, but not inside a class (unless it's a constructor, initializer block, etc.) – ktm5124 Mar 01 '14 at 06:28
  • Please tell the reason.For sure there should be a reason for this. – Mohsen Kamrani Mar 01 '14 at 06:34
  • *"So do you mean compiler considers classes C and D as variables?"* Yes, but, actually, as statements. The point is when `C` is declared, the local variable `j` is not declared yet, thus the error. – acdcjunior Mar 01 '14 at 06:35
  • Because methods are supposed to be a series of instructions, where order matters. But classes are supposed to provide structure, allocating methods and variables into memory. In this case order does not matter. – ktm5124 Mar 01 '14 at 06:36
  • 2
    @ktm5124 the classloader doesn't care which source file your class was in. Classes A, B, C and D are all separate classes loaded at different times. The fact is just that it is legal to refer to an accessible field in another class, no matter where it was declared in source code (before or after the reference) while local variables cannot be referenced before they are declared. – Erwin Bolwidt Mar 01 '14 at 06:42
  • 2
    @ktm5124 This statement is incorrect: "When class A is loaded by the classloader into memory, so is class B, because they're in the same file." – Erwin Bolwidt Mar 01 '14 at 06:50
  • @ErwinBolwidt I suspected that might be so. – ktm5124 Mar 01 '14 at 06:54