Shadowing and Using this in Java
What is Shadowing?
Local variables are variables that are declared in a method or constructor. Instance variables are variables declared in a class at the class level. Shadowing occurs when you have an instance variable with the same name as a local variable. It essentially hides the instance variable.
public class MyClass {
private boolean value = true;
public MyClass(final boolean value) {
System.out.println(value);
}
}
This class has an instance variable named value and a constructor parameter named value. When value is printed, what variable will be used? This is an example of variable shadowing. The instance variable value defined in MyClass is shadowed by the variable value in the constructor. The value that will be printed out is the value in the constructor parameter.
Shadowing is a consequence of how scoping works. Instance variables are scoped differently than local variables.
Using this
The this keyword exists to specify an instance variable when you have a local variable that shadows an instance variable. If you aren't dealing with shadowing, you shouldn't be using this to reference instance variables because it is redundant and makes the code harder to read.
Shadowing commonly occurs when you are assigning values to instance variables in a class constructor. When you do this, you usually want the constructor parameter names to match the instance variable names. This makes the code easier to understand because you are mapping one value to another using the same name.
public class User {
private int id;
public MyClass(final int id) {
this.id = id;
}
}
Local Variables
In both constructors and methods, local variables can be defined. They can have the same variable name as an instance variable.
public class User {
private int id = 0;
public void method() {
int id = 1;
// Prints 0
System.out.println(this.id);
}
}
Although this is valid with local variables, you should try to choose better variable names so shadowing isn't an issue. Local variables should be named differently than instance variables. An instance variable name describes some type of state. A local variable name should describe its intent.
public class User {
private int id = 0;
public void method() {
final int tempId = 1;
// Prints 0
System.out.println(id);
}
}
Inner Classes and Shadowing
Inner classes can have shadowing with both variables and methods since an inner class has access to the variables and methods in the outer class and vice versa. Anonymous classes and local classes are also considered inner classes. Using this always refers to the class you are in. If you are in the outer class, this refers to the outer class. If you are in the inner class, this refers to the inner class. When inside an inner class and accessing variables and methods in the outer class, using this is a little different.
public class OuterClass{
private int x = 10;
public class InnerClass {
private int x = 20;
public void print() {
System.out.println("Outer Class: " + OuterClass.this.x);
System.out.println("Inner Class: " + this.x);
}
}
}
You'll notice the syntax for this in the outer class while inside the inner class is different. This example only shows shadowing with instance variables, but the same applies to methods.
Conclusion
Shadowing is most common in constructors when you are assigning values to instance variables, although it can occur in methods as well. Using this to prevent an instance variable from being shadowed. In methods, try to use better names so shadowing isn't a problem.