Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 4

Static vs. Instance: 'static' and 'this' Keywords

Recommended resources

In our previous lesson, we established the principle of encapsulation, using access modifiers to protect an object's internal state. Every field and method we worked on belonged to a specific instance of a class—for example, the question field in riddle1 was distinct from the question in riddle2. This raises a natural question: what if you need a piece of data or a function that is shared by all objects of a class, or one that doesn't need an object to exist at all?

This lesson explores that very concept. We will differentiate between instance members, which belong to an object, and static members, which belong to the class itself. You will learn to use the static keyword to create class-level variables and methods, and the this keyword to explicitly refer to the current object instance. Mastering this distinction is fundamental in Java, especially for understanding utility classes, design patterns like Singletons, and the very structure of a Java application, including the main method.

The static Keyword: Belonging to the Class

Up to now, every field you've created has been an instance variable. When you create three Riddle objects, you get three separate copies of the question and answer fields in memory.

But sometimes, you want a variable that is shared across all instances. For this, Java provides the static keyword. A static member belongs to the class itself, not to any individual object. There is only one copy of a static variable, no matter how many objects of the class are created.

The video below offers an excellent demonstration of why this is useful. It starts by trying to count the number of "Friend" objects using an instance variable, which fails, and then shows how the static keyword provides the correct solution.

Learn the STATIC keyword in 8 minutes! 🤝

This video from Bro Code clearly illustrates the problem that static variables solve and the correct way to use them.

Watch these key segments: The problem: The instructor attempts to count objects using a regular instance variable, showing how each object gets its own separate counter. The static solution: He adds the static keyword, and suddenly all objects share one counter, which now works correctly. The proper syntax: He explains the best practice for accessing static members—using the class name itself, not an object reference. This is a crucial convention for code clarity.

Static Variables and Methods

As the video showed, static can be applied to both variables and methods.

  • Static Variables: Often used for constants (e.g., Math.PI) or for data that is shared among all instances of a class (e.g., a counter).
  • Static Methods: These are methods that can be called on the class itself, without needing to create an object. They are often used for utility functions. You've already used many of these, like Math.round() or Math.random(). You never had to write Math myMath = new Math();.

For a more formal definition and some clear examples of common use cases, please review the following resource.

6.7. Static Variables and Methods — CS Java

This CS Java article provides concise definitions and code examples for static members, including the common patterns of using them for object counters and tracking shared values like a maximum.

Please read the introductory section and the two main examples: Read the initial definition of static members. Review the object counter example. This reinforces the concept from the video. Skim the max value example to see another practical application.

The Fundamental Rule of Static Context

The most important concept to grasp is the separation between the static context (the class) and the instance context (an object). A static method, which belongs to the class, has no knowledge of any specific object instance. This leads to a critical rule:

A static method cannot directly access an instance variable or an instance method.

Why? Because if you have 100 Riddle objects, and you call a static method like Riddle.someStaticMethod(), how would Java know which of the 100 question fields to access? It can't. The static method is not operating on any particular object.

This is where your computer science background can provide a deeper understanding. Let's look at how the Java Virtual Machine (JVM) organizes memory.

This diagram shows the distinction between the Method Area and Heap Memory in the JVM. The class's static members (`Person.class`, `static int count`) are loaded once into the Method Area. Each object instance (`Person Instance #1`, `Person Instance #2`) is created in the Heap, each with its own copy of instance variables like `name`.

As the diagram illustrates:

  1. Method Area (Class Area): When the Person class is loaded, its static members (count and printCount) are stored here. They exist at the class level.
  2. Heap Memory: When you create objects (new Person(...)), they are allocated memory on the heap. Each object (Person Instance #1, Person Instance #2) gets its own space for its instance variables (name).

A static method like printName() in the diagram would cause a compile error because it lives in the Method Area and has no way to know whether to access Alice's name or Bob's name on the heap. It has no associated object.


The this Keyword: Referring to the Current Object

Now let's flip to the other side: the instance context. When you are inside an instance method or a constructor, how do you refer to the current object—the specific instance that the method was called on? For this, Java gives us the this keyword.

The this keyword is a reference to the current object. Its most common use is to resolve ambiguity between instance variables and parameters with the same name.

For instance, in a constructor:

public class Dog {
    private String name;

    public Dog(String name) {
        // 'this.name' refers to the instance field.
        // 'name' refers to the constructor parameter.
        this.name = name;
    }
}

Without this.name, the line would be name = name;, which would simply assign the parameter's value to itself, leaving the instance field unchanged.

The following video provides a clear, step-by-step walkthrough of how and why this is used.

This Keyword in Java Full Tutorial - How to Use "this"

This tutorial from Coding with John focuses on the practical uses of the this keyword, particularly for resolving name collisions in constructors and setters.

Please watch the main segment on referring to the current object, from the beginning up to this point. Pay close attention to the Dog class example, as it clearly demonstrates using this in both a constructor and a setter method.


The Incompatibility of static and this

Now we can connect the two concepts. The this keyword refers to a specific object instance. A static method is not connected to any specific object instance. Therefore:

You can never use the this keyword inside a static method.

Attempting to do so results in a compile-time error, cannot use this in a static context. The following short clips explain this rule perfectly.

Learn the STATIC keyword in 8 minutes! 🤝

This is a continuation of the Bro Code video on the static keyword. It directly addresses why this is invalid in a static method.

Watch the segment from here, where the instructor tries to use this inside a static method and explains the resulting error.

This Keyword in Java Full Tutorial - How to Use "this"

This clip from the "Coding with John" video on this provides another concise explanation of the same rule from the perspective of the this keyword.

Watch the brief segment from here, which explains why it makes no sense to use this in a static method.


Your Turn: Applying static and this

Let's refactor your Riddle class to use both static and this, putting these concepts into practice.

Instructions:

  1. Add a Static Counter:

    • Open your Riddle.java file.
    • Add a private static integer field to count how many riddles have been created. Initialize it to 0.
      private static int riddleCount = 0;
      
    • In your Riddle constructor, add a line to increment this static counter each time a new Riddle object is created.
      riddleCount++;
      
    • Create a public static method called getRiddleCount() that returns the value of riddleCount. Since the method is static, it can access the static variable.
      public static int getRiddleCount() {
          return riddleCount;
      }
      
  2. Use this in the Constructor:

    • In the last lesson, your constructor likely took no arguments. Let's modify it to be more robust and use this.
    • Change the signature of your Riddle constructor to accept the question and answer as parameters.
      public Riddle(String question, String answer) {
          // ...
      }
      
    • Inside the constructor, use the this keyword to assign the parameter values to the instance fields.
      public Riddle(String question, String answer) {
          this.question = question;
          this.answer = answer;
          riddleCount++; // The line you added earlier
      }
      
  3. Update Main.java:

    • Open your Main.java file. Your old new Riddle() calls will now show an error because the constructor requires arguments.
    • Update your object creation calls to pass in the riddle text.
      Riddle riddle1 = new Riddle("I have cities, but no houses; forests, but no trees; and water, but no fish. What am I?", "A map");
      Riddle riddle2 = new Riddle("What has to be broken before you can use it?", "An egg");
      
    • At the end of your main method, add a line to print the total number of riddles created. Call the static method directly on the Riddle class.
      System.out.println("Total riddles created: " + Riddle.getRiddleCount());
      
  4. Run and Verify: Run your Main class. You should see the output from your riddles, followed by the line "Total riddles created: 2".

You have now successfully used a static variable for shared data, a static method for class-level functionality, and the this keyword for disambiguating instance fields within a constructor.


Key Takeaways

  • Instance Members: Belong to a specific object. Each object gets its own copy. They are accessed via an object reference (e.g., riddle1.printQuestion()).
  • Static Members: Belong to the class itself. Only one copy exists, shared by all objects. They are accessed via the class name (e.g., Riddle.getRiddleCount()).
  • The this Keyword: A reference to the current object instance. It is used inside instance methods and constructors, often to distinguish between instance fields and parameters.
  • The Core Rule: Static methods operate at the class level and have no this reference. Therefore, they cannot directly access instance members.

What's Next?

We've now defined how objects are constructed and how their members can be either instance-specific or shared at the class level. In the next lesson, we will explore another fundamental pillar of OOP: inheritance. You will learn how to create new classes that inherit properties and behaviors from existing ones using the extends keyword, allowing you to create hierarchies of related classes and reuse code effectively.