The Java language has a standard vocabulary of words, including words like "class", "int", "extends", and punctuation like curly braces, commas, semicolons, parentheses, etc. When you create a variable, you're (temporarily) adding a new word to Java's vocabulary. If you were teaching Spanish to a friend, you might at one point say "Here's a new word: ventana. It's a feminine noun, and it means 'window'." Similarly, when you teach Java a new word, you have to be very clear that you are giving it a new word, and you have to tell Java what kind of a word it is. This is all done by typing the name of the type (or class) of the variable, then a space, then the (new) name of the variable. Here are two examples:
int x Person profOnce this is done correctly, you should be able to refer to that name later on in the same file and Java will know what you're talking about. Note that once you've already specified the type of the variable, you must not specify it again when you use it. For example,
class Dummy { void doSomething (int aParameter) { int aLocalVariable; aLocalVariable = aParameter; // no problem int aLocalVariable = aParameter; // illegal: aLocalVariable is already declared aLocalVariable = int aParameter; // illegal: aParameter is already declared anotherLocalVariable = aParameter; // illegal: anotherLocalVariable has not been declared yet int anotherLocalVariable = aParameter; // no problem } }
There are three kinds of variables in Java: parameters, local variables, and instance variables. All three of them are declared with exactly the same syntax as above: a type (or class) name, a space, and the new name of the variable. They differ in where you put all this.
class Dummy { String anInstanceVariable; int anotherInstanceVariable, andYetAnother; void doSomething (String thisIsAParameter, int thisIsAnotherParameter) { String heresALocalVariable; int hereIsAnotherLocalVariable; // Java statements go here, and can use any of these: // "this.anInstanceVariable", "this.anotherInstanceVariable", // "this.andYetAnother", "thisIsAParameter", "thisIsAnotherParameter", // "heresALocalVariable", and "hereIsAnotherLocalVariable" . // For example, heresALocalVariable = this.anInstanceVariable + thisIsAParameter; } int doSomethingElse (int thisIsAParameter) { double heresALocalVariable; String andYetAnother; // Java statements here can use any of these: // "this.anInstanceVariable", "this.anotherInstanceVariable", // "this.andYetAnother", "thisIsAParameter", // "heresALocalVariable", and "andYetAnother" . }
The three kinds of variables differ in several interesting ways: where they are visible, how long they live, and how they get values.
Visibility | Lifetime | How do they get a value? | ||
---|---|---|---|---|
Instance variable | the whole class in which they are declared | as long as the class instance exists | assignment statement in any method in the class, most often a constructor method. | |
Parameter | the method in whose header they are declared | disappear as soon as the method in which they are declared returns | matched up automatically with arguments when method is called | |
Local variable | the block in which they are declared (usually a whole method) | assignment statement in the method, typically immediately after declaring the variable |
Parameter variables are usually easy to identify: you need a parameter for each piece of information the method will be given by its caller.
To decide whether to declare a particular variable as an instance or a local variable, ask yourself the following questions:
There are three rules for multiple variables with the same name.
For example,
class Foo { private int x; ... private double x; }is illegal because the scope of both
x
's is the
Foo
class. (Even if one of the x
's were
public
, or if they had the same type, they would still
have the same scope and this would still be illegal).
class Foo { public void doSomething (int x, int y, int x) { ... } }is illegal because both
x
's are declared as parameters to
the method, and are therefore visible throughout the method.
(Again, whether they're the same type or not makes no difference.)
class Foo { public void doSomething () { int x; int y; double x; ... } }is illegal because the scope of both
x
's is the body of the
method. Again, whether they're the same type makes no difference; it's
still illegal.
A common beginner mistake is to put a variable's type in front of its name every time you use it:
class Foo { public void doSomething (int y) { int x; ... int x = y + 3; } }As far as Java is concerned, the second
int x
is declaring
a new variable named x
in the same scope as the previous
variable named x
, which is illegal. This student
presumably meant
class Foo { public void doSomething (int y) { int x; ... x = y + 3; } }which would be perfectly legal and reasonable.
For example,
class Dummy { void doSomething (String thisIsAParameter, int thisIsAnotherParameter) { String heresALocalVariable; ... } int doSomethingElse (int thisIsAParameter) { double heresALocalVariable; ... } }Although both methods have a parameter named
thisIsAParameter
, their scopes don't overlap, so Java
doesn't care whether they have the same name: references to
thisIsAParameter
in each method apply to that method's
parameter, and there is no automatic connection between the two.
Likewise with the two variables named heresALocalVariable
.
For example,
class Foo { private int x; public void doSomething (int x, int y) { ... x = 7; this.x = 8; } }is perfectly legal: the scope of one variable
x
is the
whole class, while the other is only visible in the
doSomething
method. The reference to x
inside
doSomething
is to the parameter x
,
since its scope is smaller. The reference to this.x
, of
course, is still to the instance variable.
A common illustration of this fact is the following idiom for constructors:
class Foo { private int x; public Foo (int x) { this.x = x; } ... }This has the effect of copying the parameter into the instance variable. If you were to do the opposite:
class Foo { private int x; public Foo (int x) { x = this.x; } ... }the constructor would try to change the parameter to match the instance variable (which still has its default value of 0). It would compile without error, but would do nothing whatsoever.
For an extreme example, consider
class Foo {
private int x = 4;
public void doSomething () {
int x = 3;
System.out.println(x);
this.doSomethingElse (12);
System.out.println(x);
System.out.println (this.x);
}
public void doSomethingElse (int x) {
System.out.println (x);
x = 7;
System.out.println (x);
System.out.println (this.x);
}
}
which has three different variables named x
, all
with different scopes (one instance variable, one a parameter to
doSomething
, and one local to
doSomethingElse
).
If you call doSomething()
, the program will print out 3,
then 12, then 7, then 4, then 3, and finally 4 again. (Be sure you
understand why.)
And don't you dare turn in programs that are as confusing as this example!