Classes & Objects
Every program up to this point has used exactly one class, filled with static methods that don't belong to anything in particular. That's a fine way to write a short script, but it falls apart the moment you need to keep track of several independent, similar things at once — several bank accounts, several students, several inventory items. Classes are how Java models "several of these, each with its own data."
A class is a blueprint
A class describes what something looks like and what it can do, without actually being any specific one of those things. Think of it as a blueprint for a house: the blueprint isn't a house you can live in, but you can build as many actual houses from it as you like, each standing on its own separate lot. An object is one of those actual houses — a specific instance built from the class's blueprint, with its own data living independently of every other instance.
public class BankAccount {
String owner;
double balance;
void deposit(double amount) {
balance = balance + amount;
}
void withdraw(double amount) {
if (amount <= balance) {
balance = balance - amount;
} else {
System.out.println("Insufficient funds.");
}
}
}
owner and balance are fields — the data each account keeps track of. deposit and withdraw are instance methods — behavior each account can perform, always acting on its own balance, never anyone else's. Notice these methods aren't marked static, unlike every method in the previous lesson: static methods belong to the class as a whole, but deposit only makes sense in the context of one specific account, so it has to belong to an instance instead.
Creating and using objects
The new keyword builds an actual object from a class. You can create as many as you want, and each one keeps its own separate copy of the fields:
public class BankDemo {
public static void main(String[] args) {
BankAccount alicesAccount = new BankAccount();
alicesAccount.owner = "Alice";
alicesAccount.balance = 500.0;
BankAccount bobsAccount = new BankAccount();
bobsAccount.owner = "Bob";
bobsAccount.balance = 150.0;
alicesAccount.deposit(200.0);
bobsAccount.withdraw(300.0);
System.out.println(alicesAccount.owner + ": $" + alicesAccount.balance);
System.out.println(bobsAccount.owner + ": $" + bobsAccount.balance);
}
}
Alice: $700.0 Bob: Insufficient funds. Bob: $150.0
Depositing into alicesAccount had zero effect on bobsAccount, and vice versa — each is a fully independent object holding its own balance. That independence is the entire point of a class: the code for deposit and withdraw was written exactly once, but it works correctly no matter how many accounts you create, because each call operates on whichever object you called it through.
Why bundle data and behavior together
You could, in principle, keep balance as a separate variable and write a standalone static method that takes a balance and an amount and returns a new balance. Nothing stops that from working for a single account. It falls apart once withdrawal rules get more complicated — a minimum balance requirement, an overdraft fee, a transaction log — because now every piece of code that touches an account's balance needs to know and correctly apply all of those rules itself. Bundling the data with the methods that are allowed to change it means the rules live in exactly one place: inside the class. Anyone using a BankAccount just calls withdraw and trusts it to do the right thing, without needing to know how.
Fields default to zero, false, or null
If you create a BankAccount and never explicitly set balance, it isn't left undefined — Java automatically initializes numeric fields to 0, boolean fields to false, and any object reference field (including String) to null. This only applies to fields on a class; a local variable inside a method gets no such default and must be assigned before it's read.
null means "no object here at all" — it's not an empty string or a zero, it's the complete absence of a reference. Calling a method on a null reference, like account.deposit(50) when account was never assigned an actual BankAccount, crashes with a NullPointerException, one of the most common errors you'll run into once objects are involved.