Variables

A recap and summary.

Declaring variables

Declaring a variable is like declaring war or your love: you are asserting that a thing now exists.

A declaration has only two required parts: the type of the variable and the name

int n;
boolean b;
String s;
ArrayList<Integer> ns;

n, b, s, and ns are now names we can use to refer to values of the types int, boolean, String, and ArrayList<Integer> respectively.

Assignment

Assigning a variable is when we give it a value.

n = 42;
b = true;
s = "hello";
ns = new ArrayList<>();

After these lines run, n, b, s, and ns all have the values given.

Initialization

Initializing a variable is just a special name for the first time we assign it a value. Often we combine declaration and initialization in one step:

int n = 42;
boolean b = true;
String s = "hello";
ArrayList<Integer> ns = new ArrayList<>();

Accessing

The whole point of defining a variable is to be able to use the name to refer to a value.

System.out.println(x * 10);

Talking about values

When we talk about code we also often use the names of variable as a stand-in for the value they name. For instance, how many times does this loop run:

for (int i = 0; i < n; i++) {...

We say “n” times meaning it will run as many times as the value of the variable n when that line of code executes.

Scope

The scope of a variable is the part of the program in which it can be referred to.

From the point of view of scope there are two kinds of variables member variables and local variables.

Member variables

public class Foo {
  public static int X = 100;
  public int y = 42;
}

X and y are both member variables. Their scope is unlimited. (I.e. they can be referred to anywhere.)

Inside the class we can use just their the name X or y.

Outside the class via the class name for X and via some instance of Foo for y: Foo.X or myFoo.y.

Accessibility of member variables

public class Foo {
  private static int X = 100;
  private int y = 42;
}

Member variables can be marked private which prevents them from being referred to outside of the body of the class in which they are defined.

Technically accessibility and scope are different things but the practical effect is the same as if their scope was limited to the class.

Local variables

public class Foo {
  public void bar(int y) {
    int z = 100;
    System.out.println(x + y * z);
  }
}

y and z are local variables. Their scope is limited to the body of the bar method.

Other y and z variables can exist elsewhere but would be different variables.

Even more local variables

public class Foo {
  public bar(int n) {
    for (int i = 0; i < n; i++) {
      double r = Math.random();
      System.out.println(r * i);
    }
  }
}

n is a local variable scoped to the body of bar.

i is a local variable whose scope is the body of the for loop plus the loop header.

r is a local variable whose scope is the body of the for loop.

Shadowing

Scopes can overlap e.g. the body of a method is contained within the body of the class in which it is defined.

Thus it’s possible for variables with the same name to exist in overlapping scopes.

Normal shadowing

public class Foo {
  private int x;
  public Foo(int x) {
    this.x = x;
  }
}

The name x names two different variables, the member variable and the parameter to the constructor.

This is a common idiom in constructors where we use this.x to specifically refer to the shadowed member variable.

A quick quiz

public class Digits {
  private ArrayList<Integer> digitList;

  public Digits(int number) {
    ArrayList<Integer> digitList = new ArrayList<>();
    // stuff with digitList
  }

  public String toString() {
    return digitList.toString();
  }
}

Why we we get a NullPointerException when toString is called?

What it should be

public class Digits {
  private ArrayList<Integer> digitList;

  public Digits(int number) {
    digitList = new ArrayList<>();
    // stuff with digitList
  }

  public String toString() {
    return digitList.toString();
  }
}

Leave the declaration of the member variable.

Initialize the variable in the constructor.

Alternatively

public class Digits {
  private ArrayList<Integer> digitList = new ArrayList<>();

  public Digits(int number) {
    // stuff with digitList
  }

  public String toString() {
    return digitList.toString();
  }
}

Declare and initialize the member variable in one step.

Member vs local

Member Local
Declared At the top level of class As parameters and within the bodies of methods and constructors
Scope Anywhere they are accessible Only within nearest set of enclosing {}s or the defining construct (e.g. method body for method parameters and whole for loop for loop variables.)
Default value if not initialized Zero value for type: 0, 0.0, false, or null None. Must be initialized before use.
Can be shadowed? Yes No
(Java is especially picky about this)
Can be public or private? Yes No
Can be static? Yes No
Can be accessed via this or class name? Yes No

Vocabulary

declaration where we create a variable with a specific type and name
member variable a variable declared at the top-level of class.
local variable a variable declared within a method or constructor
scope the part of a program where a variable name is meaningful
initialization when we we assign a value to a variable for the first time