Lesson 6 of 13
Classes & OOP
Learn how to define classes, create objects, and use constructors, inheritance and overriding. Classes are how almost all Java code is organised.
// Abstract class
public abstract class Animal {
private String name; // private — encapsulation
public Animal(String name) { this.name = name; }
public String getName() { return name; } // getter
public abstract String speak(); // subclasses must implement
public String describe() { // can be overridden
return name + " says " + speak();
}
}
// Interface
public interface Trainable {
void learn(String trick);
List<String> getTricks();
default String showTricks() { // default implementation (Java 8+)
return String.join(", ", getTricks());
}
}
// Concrete class
public class Dog extends Animal implements Trainable {
private List<String> tricks = new ArrayList<>();
public Dog(String name) { super(name); }
@Override
public String speak() { return "Woof!"; }
@Override
public void learn(String trick) { tricks.add(trick); }
@Override
public List<String> getTricks() { return tricks; }
@Override
public String describe() {
return super.describe() + " (knows " + tricks.size() + " tricks)";
}
}
// Java 16+ records — immutable data classes
record Point(double x, double y) {
// Compact constructor for validation
Point {
if (Double.isNaN(x) || Double.isNaN(y))
throw new IllegalArgumentException("Coordinates cannot be NaN");
}
public double distance() {
return Math.sqrt(x * x + y * y);
}
}// Generics
public class Pair<A, B> {
private final A first;
private final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() { return first; }
public B getSecond() { return second; }
@Override
public String toString() {
return "(" + first + ", " + second + ")";
}
}
// Generic method
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
// Main usage
public static void main(String[] args) {
Dog dog = new Dog("Rex");
dog.learn("sit");
dog.learn("shake");
System.out.println(dog.describe());
System.out.println(dog.showTricks());
Point p = new Point(3, 4);
System.out.println("Distance: " + p.distance());
Pair<String, Integer> pair = new Pair<>("Alice", 30);
System.out.println(pair);
System.out.println(max("apple", "banana")); // banana
System.out.println(max(42, 17)); // 42
}Common question
Does Java pass objects by reference?
A Java of a type holds a to an object, not the object itself. Assignment copies the reference, so two variables can point at one object. Passing to a copies the reference too, so the method can change the object but cannot repoint the caller's variable. Primitives hold their values directly and are copied outright.
Two rules prevent most beginner : compare objects with equals (and override it together with hashCode), and be deliberate about whether a method changes its or returns a new value. classes, like and the newer records, make both questions go away.
Source: The Java Language Specification says that when a method is invoked, the values of the actual argument expressions initialise newly created parameter variables. Java copies values; it never passes the caller's variable itself.
Common mix-ups
Each of these sounds reasonable. Think about why it is wrong, then open the explanation.
Changing an object's field inside a method changes it for the caller, so that's pass by reference.
Comparing two strings with == compares their characters.
An is just a class with no implementation.
Tip: use the ← and → keys to move between lessons.