5.2. Instance and Static Methods

We explored configuring data within classes with fields and properties. Now let’s turn our attention back to class behavior (methods).

5.2.1. Quick Method Review

In the last chapter, we learned that:

  1. A method belongs to a class and performs an action.

  2. Methods cannot stand on their own—they must be part of a class.

  3. To call a method on an object, use dot notation:

    objectName.methodName(arguments);
    
  4. Access modifiers apply to methods:

    1. private methods as those that are NOT useful outside of the class but contribute internally to helping the class behave as desired or expected.
    2. public methods contain code that other classes need to use when they implement the class containing those methods. Make methods public only when you expect other classes to use them, and when you are committed to maintaining those methods for other programs.

Let’s take a closer look at two different types of methods—both of which we have used in earlier examples.

5.2.2. Instance Methods

As we learned in the last chapter, instance methods define the behaviors that are unique or specialized to each class. Every object created from a class will carry a copy of these methods.

Instance methods depend on the data stored in an individual object. If two objects call the same method, the results will vary when the objects contain different data.

Let’s add a couple more instance methods to our Student class.

What are the behaviors that our Student class should have? To start, it makes sense that when a student takes a class and earns a grade, their data should be updated accordingly. Additionally, it would be nice to easily identify the grade level of a student—freshman, sophomore, junior, or senior.

The framework for these new methods is shown in the Student class below, but each method is missing some code. Filling in that code is left for you to do in the chapter exercises.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class Student {

   private static int nextStudentId = 1;
   private String name;
   private int studentId;
   private int numberOfCredits;
   private double gpa;

   public Student(String name, int studentId,
         int numberOfCredits, double gpa) {
      this.name = name;
      this.studentId = studentId;
      this.numberOfCredits = numberOfCredits;
      this.gpa = gpa;
   }

   public Student(String name, int studentId) {
      this(name, studentId, 0, 0);
   }

   public Student(String name) {
      this(name, nextStudentId);
      nextStudentId++;
   }

   public String studentInfo() {
      return (this.name + " has a GPA of: " + this.gpa);
   }

   public void addGrade(int courseCredits, double grade) {
      // Update the appropriate fields: numberOfCredits, gpa
   }

   public String getGradeLevel() {
      // Determine the grade level of the student based on numberOfCredits
   }

   /* getters and setters omitted */

}

Tip

When creating your classes, think about the behaviors that you want to make available, as well as the access level of those methods.

5.2.3. Static Methods

We’ve already used static methods quite a bit in this course, all the way back to our first Java method:

public static void main(String[] args) {}

Now let’s examine them in the context of what we’ve recently learned about classes.

Just like static fields, static methods belong to the class as a whole, and not to any of the specific instances of the class. Thus, they are sometimes also called class methods. A static method is essentially the opposite of an instance method, since the two cases are mutually exclusive. Instance methods rely on each object’s specific data, while static methods must NOT rely on data from a specific object.

We call a static method by preceding it with the class name and using dot-notation. Here’s an example that we looked at previously.

Examples

HelloMethods.java

1
2
3
4
5
6
7
8
public class HelloMethods {

   public static void main(String[] args) {
      String message = Message.getMessage("fr");
      System.out.println(message);
   }

}

Message.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Message {

   public static String getMessage(String lang) {

      if (lang.equals("sp")) {
            return "¡Hola, Mundo!";
      } else if (lang.equals("fr")) {
            return "Bonjour, le monde!";
      } else {
            return "Hello, World!";
      }
   }
}

The call occurs in line 4: Message.getMessage("fr"). We call the static getMessage without needing an instance of the Message class. Instead, we use the name of the class itself.

Warning

It is technically allowed to call a static method using an instance of a class: myObject.someStaticMethod(). However, best practice recommends using the class name instead: ClassName.someStaticMethod(). This makes it clear to other coders that you are calling a static method.

A method should be static when it does NOT refer to any instance fields of the containing class (it may refer to static fields, however). These methods tend to be utility-like (e.g. carrying out a calculation, or using or fetching some external resource).

5.2.4. Accessing Static vs. Instance Fields

One common error new Java coders encounter reads something like non-static variable cannot be referenced from a static context. This occurs when a static method tries to call an instance variable.

Why can’t we do this? Static methods can be called from anywhere (depending on their access modifier), and they do NOT require us to create an object for a particular class. However, these methods must be independent of any values unique to a particular object.

For example, if we have a Circle class, then we can define and call a static area method without creating a new object: Circle.area(radius). Since the area of a circle is just, PI*radius*radius, we can pass in the argument when we call the method. The method does not depend on any value stored within a specific Circle object.

Now let’s assume we define a Car class with an instance variable for color. The value of this field will NOT be the same for every Car object we create. Thus, trying to call a static method like Car.printColor() results in an error. Since there is no single value for color that applies to every object, trying to access it from outside of the class does not work. To print the color of a Car object, we must call the method on that specific object: myCar.printColor().

Instance fields can only be called by instance methods.

Note

While static methods cannot access instance variables, an instance method CAN access a static variable. Why?

5.2.6. Check Your Understanding

Question

Assume that we add two methods to a Pet class—public String makeNoise() and public static void increaseAge(). Which of the following statements is true?

  1. The makeNoise() method can be accessed outside of the Pet class, while the increaseAge() method cannot.
  2. Each Pet object carries a copy of the makeNoise() method but NOT a copy of the increaseAge() method.
  3. The increaseAge() method can be accessed outside of the Pet class, while the makeNoise() method cannot.
  4. Each Pet object carries a copy of the increaseAge() method but NOT a copy of the makeNoise() method.

Question

Explain why it IS possible for an instance method to access a static field.