Object Oriented Programming attempts to make programming more understandable and intuitive to humans by introducing the idea of an object. In the real world, we can group objects into categories which all have the same properties and behaviors, but each object might have a different value for a particular property. For example, all bicycles have a frame made out of some material; however, different bicycles might be made out of different materials.
OOP lets us define our own 'categories' of objects, which we call classes.
These classes will have properties and behaviors: for example, if we made a bicycle class, it might have a wheelSize property
, a handleShape property
, etc.
We can then make specific instances of those classes, which actually have values for those variables; each instance we make could have different values, but they'd all be the same type of object: a bicycle.
Another way to think of it is like this: a class is like a blueprint or a general description of what properties and behaviors an object might have; it's the idea of what a bicycle is. An instance of an object is an actual thing you'd encounter out in the real world; it's the bicycle which might almost knock you off the pavement while you're on your evening walk. The bicycle idea tells us that bicycles have a frame which has a color, but different bicycles can have different color frames.
Fields and methods are the technical terms for the properties and behaviors we define for our objects.
Fields take the form of variables, while methods are functions.
Suppose we want to make a Person
class; the fields of that class would likely be things such as height
, weight
, eye_color
, hair_color
, etc.
The methods of that class could be things like eatBreakfast()
, sleep()
, brushTeeth()
, etc.
Another example could be a Vehicle
class: our fields could be things like numWheels
, numSeats
, speed
, directionOfTravel
. etc.
Our methods would likely be things like turnRight()
, turnLeft()
, accelerate()
, etc.
When we have a class defined (or we import one from someone else's library - yes, we can import objects as well as functions), we can make an object of that class by instantiating it, thereby making an instance of that class. Remember, an instance of a class is like a concrete item you can interact with, while the class definition is like the idea of an object..
Then, we can 'call' the class's methods on that instance to modify its variables using the dot operator.
Let's suppose we have a Vehicle
object already instantiated called myVehicle
(objects, like variables and datastructures, need names for us to refer to):
myVehicle.decelerate()
myVehicle.turnLeft()
myVehicle.accelerate()
Presumably, the decelerate()
method will reduce the vehicle's speed, the turnLeft()
method will have some code that works out which way the vehicle is heading and makes the appropriate changes to its variables, and the accelerate()
method will increase the vehicle's speed.
Remember that there is no vehicle anywhere in the computer: the myVehicle
object is just a datatype which we have defined so that we can more easily think about what our code is doing.
Also notice that if we have two vehicles, say, myVehicle
and yourVehicle
, they will have the same variables, so they will both have a speed
, directionOfTravel
, etc, but the values can and likely will be different.
Calling a instance of a class's method on an instance of the class only modifies the variables of that instance, just like pressing the brake pedal in your car only affects the speed of your car, not the cars around you, and certainly not every car in the entire world.
The idea of inheritance is powerful in OOP because it allows us to define the relationships between classes, further increasing the understandability of software. For example, we here in the real world know that a Car is a type of Vehicle; thus, it could be said that a car 'inherits' some of the traits that a vehicle has. Similarly, we know that Student is more likely than not a type of Person, and a Bird is a type of Animal, etc etc.
Many things seem to be related to other things, and expressing this relationship can allow us to make our code more understandable, as well as preventing duplicated code.
For example, we can define a Car
class to inherit from a Vehicle
class, which will mean that all attributes and behaviors of the Vehicle
will automatically transfer over to the car.
This might be useful if we have a Car
class and a Bike
class which both share attributes or behaviors, such as the accelerate()
method.
Anything that is shared between these two classes can be put in the Vehicle
class, and if both Car
and Bike
inherit from the Vehicle
class, they'll both have it.
Essentially, instead of having to write two identical accelerate()
methods for the two classes, we can just write one;
the more things that are in common, the bigger the time and complexity savings.
We call the class which inherits fields and methods the subclass or child class, while the class it inherits from is called the superclass or parent class.
In some programming languages, like Java, classes can have at most one superclass, while in others, like Python, classes can have an arbitrary number of superclasses.
Interfaces, like inheritance, allow us to write cleaner, more efficient, and more understandable code. Just like a class might inherit attributes or behaviors from its superclass, a class can implement behaviors from an interface. An interface is different from a class in that it can only describe behaviors, not attributes. The reason an interface is useful is because it can allow many disparate classes, which may not fall into a neat subclass-superclass hierarchy, to share code that might otherwise have to be written multiple times.
Let's think of a concrete example: many things can be directed by a driver of some type, such as horses, cars, planes, trains, drones, pogosticks, skateboards, etc; however, it isn't obvious what parent class these classes could have.
What parent class could a horse, a pogostick, and a drone have in common?
We don't want to have to write the code to accelerate, decelerate, and turn for every single class, so we can instead wrap it in an interface.
For example, our interface could be called Steerable
, and it could contain the methods needed to steer an object.
Just as inheritance allows us to group and structure the relationships between classes based on linear inheritance of characteristics, interfaces allow us to group and relate classes by the behaviors which they share. Additionally, there are normally no restrictions on how many interfaces a class can implement, while many times a class can only inherit from one parent.
OOP allows us to make really clean, efficient, and understandable code using the idea of an object, which mimics a real-world object in that it has properties and behaviors, known as fields and methods. An object definition (class definition) is like a blueprint or the idea of what makes a thing a thing, while an instance of an object is more concrete, like something you can run into in the real world. Objects' relationships can be expressed in code by using inheritance or interfaces, which enhance understandability while reducing the need for duplicated code.
Finally, I want to note that even though all the sample objects on this page were actual real-world things, that isn't necessary.
OOP can be used to program at very abstract levels, and creating objects which don't necessarily exist in the real world, such as an ImageBuffer
, is fine, and in fact very useful.
Congratulations! You've read through all of these pages and now know a heck of a lot more than you did when you started. Now, it's time to start actually programming, so head on to the Java Setup or Python Setup pages to set up your workspace. After than, you can head to the Java or Python pages to start learning how to actually code.