Close
Close Window

MHC S25 COMSC 205: Data Structures

Chapter 3 Intro to Java III: Classes

«  3.2. Additional Java Information   ::   Contents   ::   4.1. Introduction to Inheritance  »

3.3. Variable Scoping

3.3.1. Variable Scoping

This section discusses exactly where a user-defined name can be accessed. The scope of a user-defined name is the region of source code where the name is visible and can be used.

3.3.1.1. Local Scope

Recall that mutator methods (or “setters” as they’re often called) are used to change the values of private fields in a class. For example:

public class Cat
{
    private String color;

    // ...

    public void setColor(String newColor)
    {
         color = newColor;
    }
}

This setColor() method makes use of both a field and a parameter. It is important to note that there is a difference in where these two types of variables can be used. The scope of a variable or method refers to where it can be used in a program.

A parameter’s scope is limited to the body of the method in which it is declared. Parameters are local variables which are declared in the parameter list of a method’s header and which have initial values specified by the arguments in a method call. For example, if we had an object of type Cat called c, we could call the setColor() method like so:

c.setColor("Black");

When we write the method, we declare the variable newColor, and when we call the method here, we set s equal to the string “Black”. If we wanted to call the method again, we would need to provide a new value for the variable newColor.

c.setColor("Black");
c.setColor("Grey");

Such values do not carry over between method calls.

The scope of a parameter is the same as the scope of a variable declared at the very beginning of the body of a method. Once the flow of execution leaves a method, its parameters and other local variables cease to exist. The scope of local variables is referred to as local scope.

Local Variables. Local variables, that is, parameters and variables declared in the body of a method, have local scope which extends from the point at which they are defined to the end of the block of code in which they are defined. In particular, the scope of a parameter is the entire body of the method in which it is declared.

It would be a syntax error to refer to a method’s parameters or other local variables from outside the method.

3.3.1.2. Block-Level Scope

Variables that are declared in the body of a method have scope which extends from the point where they are declared to the end of the block of code in which they are declared. When a local variable is declared at the beginning of a method, it has the local scope discussed above.

However, local variables are not restricted to the beginning of a method, and their declarations can be placed elsewhere, which can affect their scope. When control structures like if-statements or loops are involved, scope can be a bit more specific.

public void exampleMethod(int x)
{
    if (x % 2 == 0)
    {
        int value = 4;
    }
    value = value + 2; // This will not work!
}

Variables declared inside the curly braces ({}) of a control structure like a loop or conditional only exist within those curly braces. The method above would not work as the variable value is only declared and initialized inside the if statement’s true branch, and that variable ceases to exist when the corresponding closing brace marking the end of the if statement’s true branch is reached. As a result, its name is no longer visible once execution has left the block (the pair of braces) where it is declared. Any attempt to use the variable outside of the braces where it is declared will result in a compiler error, since the variable is no longer visible or accessible–no longer “in scope”.

The same is true for looping structures:

for (int i = 0; i < 12; i++)
{
    System.out.println(i);
}
i = i + 1; // This will not work!

The variable i is defined as part of the for loop and its scope is the body of the for loop–the braces surrounding the loop’s body. The variable i ceases to exist after the for loop is finished.

To get around this issue, you will sometimes see code where a variable is declared before a control structure, so that it can be accessed inside the control structure and also after it.

public void exampleMethod(int x)
{
    int value = 0;
    if (x % 2 == 0)
    {
        value = 4;
    }
    value = value + 2;
}

We could also do something similar with a for loop:

int i = 0;
for (i = 0; i < 12; i++)
{
    System.out.println(i);
}
i = i + 1; // This will work!

3.3.1.3. Class Scope

By contrast, fields and all methods have scope that extends throughout the entire class, that is, class scope. They can be used in the body of any method and in the expressions that assign initial values to class level variables.

Class-Level Variables. Fields and methods have class scope, which extends throughout the class.

3.3.1.4. A Common Misconception

After declaring a variable it is tempting to use to both the variable name and the variable’s type whenever referring to it. For example:

public class Cat
{
    private String color;

    // ...

    public void setColor(String newColor)
    {
         String color = newColor;
    }
}

This setter will not change the value of the field color. To Java, whenever the type of a variable is included, you are declaring a variable. Java will allow you to declare variables with the same name, as long as they are in different scopes. In the code above, there is a field called color with class-level scope, and a local variable called color that only exists within the setColor() method.

Even though these variables have the same name and type, they are different. Changing one will not change the other.

3.3.1.5. A Note on Naming

As we saw above, Java can handle having two variables with the same name and type when they are declared in different scopes. This can also lead to confusion. For example, we could have two String variables called color. One a field and one a parameter.

public class Cat
{
    private String color;

    // ...

    public void setColor(String color)
    {
         color = color;
    }
}

This code would compile but it is not advisable to use such naming conventions. This is because it is not clear if the field color is being set to the parameter color or vice-versa, or something else entirely. Let’s take a look at what is happening here by adding a few print statements:

public class Cat
{
    private String color;

    public Cat()
    {
        this.color = "Black";
    }

    public void setColor(String color)
    {
        color = color;
        System.out.println(this.color);
        System.out.println(color);
    }

    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setColor("Green");
    }
}

In this example, whenever we make a new Cat object, the value of the field color is set to “Black” at first. When we run the main method with setColor("Green") we see an interesting result in our print statements:

$ javac Cat.java
$ java Cat
Black
Green

The first thing to be printed out is this.color. Which we see is “Black”. The value of the field was not changed to “Green”! This means that when we write color = color we know that the field color was not on the left side of the assignment operator.

One might assume, then, that the parameter color is the value on the left side of the assignment operator. This would mean that the parameter was changed from “Green” to “Black”. But our second print statement tells us otherwise. When we print out the parameter color we see it is still “Green”. This means that the field color was not on the right side of the equals sign either!

What happened in this code is that we set the parameter variable color equal to itself–meaning nothing changed!

Generally, the best way to avoid such confusion is to give your variables distinct names like we did initially:

public void setColor(String newColor)
{
    color = newColor;
}

Alternately, if for some reason you must use the same variable name at two different scope levels, using the modifier this will help clarify which variable you are referring to:

public void setColor(String color)
{
    this.color = color;
}

Now, the field color is on the left side of the assignment operator and the parameter color is on the right. So, if we ran setColor("Green"); the field color would be changed from “Black” to “Green”.

You will sometimes see this convention in setter methods or constructors, where the programmer has intentionally used the same name for both the parameter and the field, to communicate the intent that the parameter is the value that will be stored in the field. When using this approach it is mandatory to alway include this. as a prefix when referring to the field name, because otherwise, all uses of the name would refer to the parameter only.

3.3.2. Summarizing Scope Concepts

Note

The readings for this semester sometimes have interactive widgets for you to practice concepts. These exercises are optional and are not graded, but we encourage you to try them out.

If anything is confusing or if you have questions about the exercises, we encourage you to post to Ed!

3.3.3. Check Your Understanding: Scope

3.3.4. Syntax Practice: Scoping

   «  3.2. Additional Java Information   ::   Contents   ::   4.1. Introduction to Inheritance  »

Close Window