Classes & objects
Every pattern on this site is a sentence written in one language: objects, inheritance, composition, interfaces. If that vocabulary is fuzzy, the patterns read like magic incantations - memorable, but unusable. Ten minutes here saves you the rest of the site.
Classes, objects, instances
A class is a blueprint. An object is a thing built from it, and "instance" is just the word
for that relationship - Oscar is an instance of Cat. The class says every cat has a
name, a sex, an age and a color, and that every cat can breathe, sleep, run and meow. Your
cat Oscar fills in the values. The three words describe one idea from three angles: the
class is the plan, the object is the thing, and "instance" names the act of building one
from the other.
Members: fields and methods
Fields and methods together are the class's members. The data currently sitting in an
object's fields is its state; what its methods let it do is its behavior. Oscar and
your neighbor's Luna are the same class and completely different objects, because state is
per-object and behavior is per-class - both cats can meow(), using the exact same method,
but only one of them is three years old.
Try it yourself: sketch a Car class instead of Cat - three fields and two methods
it would need. Then imagine two Car objects side by side. What is different between
them, and what is identical because it lives on the class rather than the object?
Constructors and initialization
A constructor is the one method whose entire job is to leave an object in a valid state the
moment it exists - no half-built Cat with a name but no age should ever be visible to
anything else. That is why constructors typically demand their required fields as
parameters rather than leaving them to be set one at a time after the fact: a two-step
"construct, then configure" dance always has a window where the object is observable but
incomplete.
Inside a constructor (and inside any instance method), this - self in Python - refers
to the specific object the method was called on. It is what lets name = name inside a
constructor mean something other than nonsense: this.name = name assigns the parameter to
this particular object's field, not to some other Cat's.
Static vs instance members
Every field and method discussed so far belongs to an instance - it exists once per
object. A static member belongs to the class itself, and there is exactly one copy of
it no matter how many objects exist. Cat.totalCatsCreated is shared by every cat; each
cat's own name is not.
Static earns its keep for things that are genuinely about the type, not any one object: a
counter of how many instances exist, a factory method (Cat.fromJson(data)), or a pure
utility function that needs no object state at all (Math.max(a, b)). It turns into a code
smell the moment it is used to fake global mutable state, or to bolt a function onto a class
that has nothing to do with any particular instance of it - a static method that secretly
depends on static fields being set in some other order elsewhere in the program is the
static-member equivalent of a global variable, with the same debugging cost.
Try it yourself: would a generateId() method used only inside a constructor be a
better fit as static or instance? What about a compareTo(otherCat) method that only reads
this and its argument, touching no shared state at all?
Class hierarchies
Once you notice dogs also have a name, a sex, an age and a color, and also breathe and
sleep, the shared parts want a home. That home is a base class - Animal - with Cat and
Dog extending it and contributing only their differences: meow() here, bark() there.
Animal hierarchy.The parent is the superclass, the children are subclasses, and a subclass inherits
every field and method the superclass defines - Cat gets breathe(), eat(food),
run(destination) and sleep(hours) for free just by extending Animal, on top of
whatever it adds itself. A subclass can also override an inherited method: Dog could
redefine run(destination) to add a burst of speed while still calling the superclass's
version for the rest, or replace it outright. Either way, the object that comes out of
new Dog(...) has everything Animal defines plus Dog's own additions, with run
resolved to whichever version applies.
Push the idea one level up and Animal and Plant both descend from Organism. A Cat
then inherits from everything above it. That stack is a hierarchy, and it is useful right
up until the moment it is not - see Class relationships and
Design principles for what replaces it once a hierarchy tries to
model more than one dimension of variation.
Try it yourself: extend the Organism tree with a Fungus branch that shares
almost nothing with Animal or Plant except being alive. At what point does forcing
it under Organism start to feel like the wrong tool, and what would you reach for
instead?
Check yourself
Oscar and Luna are both Cat objects. What is different between them, and what is shared?