A local variable declaration looks a bit like a statement in that it ends with a semicolon, but it generates no code. Instead, it causes the compiler to allocate a local variable slot (or two, in the case of long or double declarations). The declaration gives the compile-time type of all values read from that variable. Also, all values written to that variable must conform to compile-time type. A compiler may use any of a variety of strategies to allocate local variables to slots in the resulting JVM code. Generally, the compiler tries to minimize the number of slots used, because that makes for better performance. In Java, local variables are scoped, which means that a local variable definition is restricted to the block in which they were declared. (Recall that a block is a set of statements enclosed in curly braces). Consider this method definition: void foo(int a, long b) // Declares a and b { String name = "Joshua";// Declares name boolean state = false; // Declares state while(state) { String output = "Hello, world"; // Declares output System.out.println(output); state = true; } if(name == null) { String msg = "No name"; // Declares msg int output = b-a; // Declares output System.out.println(output); } } Figure 10.3 is a diagram of the scopes and the local variables in each. Figure 10.3. Scopes of method fooIn this code there are three different scopes: the outermost scope is the whole body of the method. It contains two other scopes: the one inside the while and the one inside the if. Notice that you can have two different variables with the same name in different scopes. They can even have different types. Both the inner scopes contain an output; it is a String in one place and an int in the other. For each scope, the compiler allocates the variables to local variable slots. When a scope terminates, later scopes may reuse those local variable slots. All the code within that scope uses those assignments. Each enclosed scope incorporates the assignments from the enclosing scope. For example, the compiler might allocate local variable slots as in Table 10.4. This information does not need to be explicitly stated within an Oolong program. However, it can be provided for debugging purposes using the .var directive:
.var 0 is a I .var 1 is b J .var 3 is name Ljava/lang/String; .var 4 is state Z .var 5 is output Ljava/lang/String; from scope1begin to scope1end .var 5 is message Ljava/lang/String; from scope2begin to scope2end .var 6 is output I from scope2begin to scope2end scope1begin: ;; Code within the body of the while scope scope1end: scope2begin: ;; Code within the body of the if scope scope2end: Scoping is also used to determine the compile-time types of variables. For example, there are two calls to println. Each takes a variable named output, but in the first case output is a String and in the second case output is an int. This is legal. In the first case the compiler generates code to call the method named println, which takes a String, and in the second case the compiler uses the method that takes an int. This is called overloading. For more about overloading, see section 10.9.5. |