Search⌘ K
AI Features

Creating Classes and Objects

Explore the fundamentals of object-oriented programming by learning how to define classes as blueprints and create objects as instances in Java. Understand fields and methods, use constructors for initialization, and organize code with packages to manage complex data effectively while maintaining independent object states.

Up to this point, we have relied on Java’s primitive types to store simple values like numbers and characters. However, real-world software rarely deals with isolated numbers; it models complex entities like users, bank accounts, or inventory items.

To manage this complexity, Java allows us to create our own custom data types. We define the structure and behavior of these types in a single class definition, and then we use that blueprint to build as many specific instances as our application requires.

From primitives to blueprints

If we were building a warehouse simulation, we might need to track a robot’s name and battery level. Using only primitives, we would create separate variables:

String robotName = "R2";
int robotBattery = 100;

This approach breaks down quickly if we have fifty robots. We would need one hundred unrelated variables, making it impossible to track which battery level belongs to which robot.

Java solves this with classes and objects.

  • Class: This is the blueprint or template. It defines what a “Robot” looks like (it has a name and a battery level) and what it can do.

  • Object: This is a specific instance built from that blueprint. “R2” is one object; “C3” is another.

Crucially, because “R2” and “C3” are created from the same class, they possess the exact same attributes and behavior. We do not need to rewrite the logic for batteryLevel or work() for each new robot. We write the code once in the class, and every object follows that logic automatically.

Anatomy of an Object
Anatomy of an Object

We write the class code once, but we can create thousands of unique objects from it.

Defining a class and fields

We define a class using the class keyword. Inside the class, we declare variables called fields (also known as instance variables). These fields represent the state of an object.

Note: In Java, each public class is typically defined in its own file matching the class name. For the examples below, we have created a file named Robot.java for the class definition.

Here, we define a simple Java class named Robot.

Java 25
class Robot {
// Fields (state)
String name;
int batteryLevel;
}
  • Line 1: We declare a new custom type named Robot. By convention, class names start with an uppercase letter.

  • Lines 3–4: We define two fields: name (to store text) and batteryLevel (to store an integer). Every Robot object we create will have its own copy of these variables.

Adding behavior with methods

Objects do not just store data; they perform actions. We define these actions using methods inside the class. Unlike the static methods we wrote previously, these instance methods operate directly on the object’s data. They can access and modify the fields we defined.

Java 25
// File: Robot.java
class Robot {
String name;
int batteryLevel = 100; // Default start value
// Method to display status
void introduce() {
System.out.println("Hello, I am " + name + ".");
System.out.println("Battery: " + batteryLevel + "%");
}
// Method to modify state
void work() {
System.out.println(name + " is working...");
batteryLevel = batteryLevel - 10;
}
}
  • Line 4: We assign a default value of 100 to batteryLevel. Every new robot will start fully charged.

  • Lines 7–10: The introduce method prints the specific values of name and batteryLevel for the robot calling the method.

  • Lines 13–16: The work method simulates activity by printing a message and decreasing the batteryLevel field by 10.

Instantiating objects

A class definition does not run by itself. To use it, we must create an instance of the class (an object) in memory. We do this using the new keyword.

The new keyword allocates memory for the object and returns a reference to it. We store this reference in a variable of the class type.

Java 25
// File: Main.java
public class Main {
public static void main(String[] args) {
// Create a new Robot object
Robot myBot = new Robot();
}
}

In line 5, Robot myBot declares a variable that can hold a reference to a Robot object. The = new Robot() creates the actual object in memory and assigns its address to myBot.

Accessing members with dot notation

Once we have an object reference, we access fields and methods using the dot operator (.). This allows us to read or write to the object’s fields and call its methods.

Java 25
// File: Main.java
public class Main {
public static void main(String[] args) {
// Create a new Robot object
Robot myBot = new Robot();
// 1. Accessing fields directly
myBot.name = "R2";
// 2. Calling methods
myBot.introduce();
myBot.work();
// 3. Verifying state change
myBot.introduce();
}
}
  • Line 8: We use myBot.name to assign the string “R2” to the name field of this specific object.

  • Line 11: We call myBot.introduce(), which executes the code inside the introduce method using myBot’s data.

  • Line 12: We call myBot.work(), which reduces the battery level by 10.

  • Line 15: We call the introduce() method again shows the updated battery level (90%).

Independent state

The power of object-oriented programming lies in independence. If we create multiple objects of the same class, each maintains its own storage. Changing the fields of one object does not affect the others.

Java 25
// File: Main.java
public class Main {
public static void main(String[] args) {
// Create two distinct objects
Robot bot1 = new Robot();
Robot bot2 = new Robot();
// Set unique states
bot1.name = "Alpha";
bot2.name = "Beta";
// Modify only bot1
bot1.work();
// Check states
System.out.println("--- Bot 1 Status ---");
bot1.introduce();
System.out.println("--- Bot 2 Status ---");
bot2.introduce();
}
}
  • Lines 5–6: We allocate two separate Robot objects in memory. bot1 points to the first, bot2 points to the second.

  • Lines 9–10: We assign different names. bot1.name becomes Alpha, while bot2.name becomes Beta.

  • Line 13: We call work() only on bot1. This reduces bot1’s battery to 90.

  • Lines 17 and 20: bot1 reports 90% battery, while bot2 remains at the default 100%. The state of bot2 is untouched by the actions of bot1.

Classes enable us to model systems in which many independent actors (such as robots, users, or buttons) coexist and interact without their data becoming confused. We accessed fields like name directly (bot1.name = "Alpha"). While this is simple, it leaves our data vulnerable to invalid changes.