> For the complete documentation index, see [llms.txt](https://cs61b-2.gitbook.io/cs61b-textbook-fall-2026/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cs61b-2.gitbook.io/cs61b-textbook-fall-2026/2.-defining-and-using-classes.md).

# 2. Defining and Using Classes

#### Static vs. Non-Static Methods <a href="#static-vs-non-static-methods" id="static-vs-non-static-methods"></a>

**Static Methods**

All code in Java must be part of a class (or something similar to a class, which we'll learn about later). Most code is written inside of methods. Let's consider an example:

```java
public class Dog {
    public static void makeNoise() {
        IO.println("Bark!");
    }
}
```

If we try running the `Dog` class, we'll simply get an error message:

```
$ java Dog
Error: Main method not found in class Dog, please define the main method as:
       public static void main(String[] args)
```

The `Dog` class we've defined doesn't do anything. We've simply defined something that `Dog` **can** do, namely make noise. To actually run the class, we'd either need to add a main method to the `Dog` class, as we saw in chapter 1.1. Or we could create a separate [`DogLauncher`](https://www.youtube.com/watch?v=Q-LE-jJQLTM) class that runs methods from the `Dog` class. For example, consider the program below:

```java
public class DogLauncher {
    void main() {
        Dog.makeNoise();
    }
}
```

```
$ java DogLauncher
Bark!
```

A class that uses another class is sometimes called a "client" of that class, i.e. `DogLauncher` is a client of `Dog`. Neither of the two techniques is better: Adding a main method to `Dog` may be better in some situations, and creating a client class like `DogLauncher` may be better in others. The relative advantages of each approach will become clear as we gain additional practice throughout the course.

**Instance Variables and Object Instantiation**

Not all dogs are alike. Some dogs like to yap incessantly, while others bellow sonorously, bringing joy to all who hear their glorious call. Often, we write programs to mimic features of the universe we inhabit, and Java's syntax was crafted to easily allow such mimicry.

One approach to allowing us to represent the spectrum of Dogdom would be to create separate classes for each type of Dog.

```java
public class TinyDog {
    public static void makeNoise() {
        IO.println("yip yip yip yip");
    }
}

public class MalamuteDog {
    public static void makeNoise() {
        IO.println("arooooooooooooooo!");
    }
}
```

As you should have seen in the past, classes can be instantiated, and instances can hold data. This leads to a more natural approach, where we create instances of the `Dog` class and make the behavior of the `Dog` methods contingent upon the properties of the specific `Dog`. To make this more concrete, consider the class below:

```java
public class Dog {
    public int weightInPounds;

    public void makeNoise() {
        if (weightInPounds < 10) {
            IO.println("yipyipyip!");
        } else if (weightInPounds < 30) {
            IO.println("bark. bark.");
        } else {
            IO.println("woof!");
        }
    }    
}
```

As an example of using such a Dog, consider:

```java
public class DogLauncher {
    void main() {
        Dog d;
        d = new Dog();
        d.weightInPounds = 20;
        d.makeNoise();
    }
}
```

When run, this program will create a `Dog` with weight 20, and that `Dog` will soon let out a nice "bark. bark.".

Some key observations and terminology:

* An `Object` in Java is an instance of any class.
* The `Dog` class has its own variables, also known as *instance variables* or *non-static variables*. These must be declared inside the class, unlike languages like Python or Matlab, where new variables can be added at runtime.
* The method that we created in the `Dog` class did not have the `static` keyword. We call such methods *instance methods* or *non-static methods*.
* To call the `makeNoise` method, we had to first *instantiate* a `Dog` using the `new` keyword, and then make a specific `Dog` bark. In other words, we called `d.makeNoise()` instead of `Dog.makeNoise()`.
* Once an object has been instantiated, it can be *assigned* to a *declared* variable of the appropriate type, e.g. `d = new Dog();`
* Variables and methods of a class are also called *members* of a class.
* Members of a class are accessed using *dot notation*.

**Constructors in Java**

As you've hopefully seen before, we usually construct objects in object oriented languages using a *constructor*:

```java
public class DogLauncher {
    void main() {
        Dog d = new Dog(20);
        d.makeNoise();
    }
}
```

Here, the instantiation is parameterized, saving us the time and messiness of manually typing out potentially many instance variable assignments. To enable such syntax, we need only add a "constructor" to our Dog class, as shown below:

```java
public class Dog {
    public int weightInPounds;

    public Dog(int w) {
        weightInPounds = w;
    }

    public void makeNoise() {
        if (weightInPounds < 10) {
            IO.println("yipyipyip!");
        } else if (weightInPounds < 30) {
            IO.println("bark. bark.");
        } else {
            IO.println("woof!");
        }    
    }
}
```

The constructor with signature `public Dog(int w)` will be invoked anytime that we try to create a `Dog` using the `new` keyword and a single integer parameter. For those of you coming from Python, the constructor is very similar to the `__init__` method.

**Array Instantiation, Arrays of Objects**

In Java, Arrays are instantiated using the `new` keyword. For example:

```java
public class ArrayDemo {
    void main() {
        /* Create an array of five integers. */
        int[] someArray = new int[5];
        someArray[0] = 3;
        someArray[1] = 4;
    }
}
```

Similarly, we can create arrays of instantiated objects in Java, e.g.

```java
public class DogArrayDemo {
    void main() {
        /* Create an array of two dogs. */
        Dog[] dogs = new Dog[2];
        dogs[0] = new Dog(8);
        dogs[1] = new Dog(20);

        /* Yipping will result, since dogs[0] has weight 8. */
        dogs[0].makeNoise();
    }
}
```

Observe that new is used in two different ways: Once to create an array that can hold two `Dog` objects, and twice to create each actual `Dog`.

#### Class Methods vs. Instance Methods <a href="#class-methods-vs-instance-methods" id="class-methods-vs-instance-methods"></a>

Java allows us to define two types of methods:

* Class methods, a.k.a. static methods.
* Instance methods, a.k.a. non-static methods.

Instance methods are actions that can be taken only by a specific instance of a class. Static methods are actions that are taken by the class itself. Both are useful in different circumstances. As an example of a static method, the `Math` class provides a `sqrt` method. Because it is static, we can call it as follows:

```java
x = Math.sqrt(100);
```

If `sqrt` had been an instance method, we would have instead the awkward syntax below. Luckily `sqrt` is a static method so we don't have to do this in real programs.

```java
Math m = new Math();
x = m.sqrt(100);
```

Sometimes, it makes sense to have a class with both instance and static methods. For example, suppose want the ability to compare two dogs. One way to do this is to add a static method for comparing Dogs.

```java
public static Dog maxDog(Dog d1, Dog d2) {
    if (d1.weightInPounds > d2.weightInPounds) {
        return d1;
    }
    return d2;
}
```

This method could be invoked by, for example:

```java
Dog d = new Dog(15);
Dog d2 = new Dog(100);
Dog.maxDog(d, d2);
```

Observe that we've invoked using the class name, since this method is a static method.

We could also have implemented `maxDog` as a non-static method, e.g.

```java
public Dog maxDog(Dog d2) {
    if (this.weightInPounds > d2.weightInPounds) {
        return this;
    }
    return d2;
}
```

Above, we use the keyword `this` to refer to the current object. This method could be invoked, for example, with:

```java
Dog d = new Dog(15);
Dog d2 = new Dog(100);
d.maxDog(d2);
```

Here, we invoke the method using a specific instance called `d`.

**Static Variables**

It is occasionally useful for classes to have static variables. These are properties inherent to the class itself, rather than the instance. For example, we might record that the scientific name (or binomen) for Dogs is "Canis familiaris":

```java
public class Dog {
    public int weightInPounds;
    public static String binomen = "Canis familiaris";
    ...
}
```

Static variables should be accessed using the name of the class rather than a specific instance, e.g. you should use `Dog.binomen`, not `d.binomen`.

While Java technically allows you to access a static variable using an instance name, it is bad style, confusing, and in my opinion an error by the Java designers.

#### Java Before and After 2025 <a href="#java-before-and-after-2025" id="java-before-and-after-2025"></a>

Before September 2025, Java required a fair amount of ceremony just to print something. All code had to live inside a class, printing was done with `System.out.println`, and the main method had to be declared with the full incantation `public static void main(String[] args)`. Compare the old and new versions of Hello World:

```java
// Pre-Java 25
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}
```

```java
// Modern Java (25+)
void main() {
    IO.println("hello world");
}
```

Java 25 made the simpler form official: you can now write `void main()` with no enclosing class, and use `IO.println` for printing. Many older 61B resources use the pre-2025 syntax.

In case you're curious about the old style `main` declaration, if we break it into pieces, we have:

* `public`: Indicates that this class or method can be used by any class (more on this in a later chapter).
* `static`: It is a static method, not associated with any particular instance.
* `void`: It has no return type.
* `main`: This is the name of the method.
* `String[] args`: This is a parameter that is passed to the main method.

**Command Line Arguments (extra content)**

Since main is called by the Java interpreter itself rather than another Java class, it is the interpreter's job to supply these arguments. They refer usually to the command line arguments. For example, consider the program `ArgsDemo` below:

```java
public class ArgsDemo {
    public static void main(String[] args) {
        IO.println(args[0]);
    }
}
```

This program prints out the 0th command line argument, e.g.

```
$ java ArgsDemo these are command line arguments
these
```

In the example above, `args` will be an array of Strings, where the entries are {"these", "are", "command", "line", "arguments"}.

#### Lists in Java <a href="#lists-in-java" id="lists-in-java"></a>

In programming languages, a list is an ordered sequence of objects, often represented by comma-separated values in-between brackets.

For example, in Python, one can create an empty list and append to it as follows:

```python
L = []
L.append("a")
L.append("b")
L.append("c")
print(L)
```

Let's try to write the equivalent Java program. A natural first attempt is:

```java
public class ListDemo {
    void main() {
        List L = new List();
    }
}
```

If you try to compile the code above, the compiler will complain that it "can't resolve symbol List". The simplest way to resolve this is to add an import statement:

```java
import java.util.List;

public class ListDemo {
    void main() {
        List L = new List();
    }
}
```

Unfortunately this code STILL doesn't compile. This time the compiler complains that "List is abstract, cannot be instantiated." The issue is that we need to pick a specific type of list. The most common choice is an `ArrayList`.

```java
import java.util.ArrayList;
import java.util.List;

public class ListDemo {
    void main() {
        List L = new ArrayList();
        L.add("a");
        L.add("b");
        L.add("c");
        IO.println(L);
    }
}
```

This compiles and prints `[a, b, c]`. Note that Java's method for appending is called `add`, not `append`.

Note: This code is written in a very old school style from the Java 5.0 days (circa 2002). We'll see more modern Java code (e.g. `List<String> L` in the next chapter).

#### Abstract Data Types vs. Concrete Implementations <a href="#abstract-data-types-vs-concrete-implementations" id="abstract-data-types-vs-concrete-implementations"></a>

Let's return to the distinction between a `List` and an `ArrayList`.

In introductory Python code, the programmer simply instantiates a list using `[]` syntax. A list is a list is a list.

By contrast, in Java, a `java.util.List` is an "Abstract Data Type". Any `List` is guaranteed to have all of the operations listed at <https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/List.html>.

Each implementation, e.g. `java.util.LinkedList` or `java.util.ArrayList` is a "Concrete Implementation". The underlying implementations may be radically different, but they have the exact same behavior from the perspective of the user of the `List`, i.e. from above the abstration boundary.

Why bother having multiple implementations of the same idea? Two big reasons:

* **Performance.** Different implementations are fast at different things. For example, a `LinkedList` is very fast at removing its front item, while an `ArrayList` is very slow at it.
* **Extra operations.** Some implementations offer operations beyond the basic guarantee. For example, the `Stack` implementation adds `push` and `pop`.

We'll explore these concepts in much more detail over the coming chapters.

**Imports in Java (extra content)**

Note: Imports work a bit differently in Java than in Python. It's not strictly necessary to import something in order to use it in Java; an alternate approach is to use the full canonical name of the thing you're trying to use. That is, rather than writing:

```java
import java.util.ArrayList;
import java.util.List;

void main() {
    List L = new ArrayList();
    L.add("a");
    L.add("b");
    L.add("c");
    IO.println(L);
}
```

You could instead write:

```java
void main() {
    java.util.List L = new java.util.ArrayList();
    L.add("a");
    L.add("b");
    L.add("c");
    IO.println(L);
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://cs61b-2.gitbook.io/cs61b-textbook-fall-2026/2.-defining-and-using-classes.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
