Lesson 6: Classes
Last updated
Last updated
You may have heard that Java is an object oriented language, as compared to a more procedural language like C. For our purposes, this means that a lot of the code you'll be using and writing will be based around classes and the objects they create. Object-oriented programming works very nicely with code that controls physical objects - like the motors and sensors of a robot.
Writing a class in Java is a lot like programatically creating a blueprint of a house. While a blueprint by itself doesn't do too much, you can take that blueprint and create an actual house from it later.
Let's take a look at an example House
class:
Wow, what a strange lump of code. You might have noticed that this House
class doesn't contain the main
method you've been wrapping your previous code in. That's because this House
is not a complete program - rather, it's a series of instructions on how to make a House
object.
A class is composed of methods - like setAddress()
and getAddress()
above, and fields - like the variables address
and floors
. Fields are a special term for variables within a class. These are also called member variables and member methods.
All of the House
class's fields and methods are prefixed with either public
or private
. These are called access modifiers, and they control whether other parts of your program are allowed to see and modify those fields and methods.
The public
access modifier allows a field or method to be accessed by anything that has access to the overall class. It's the least protective modifier and should be used when you don't care what accesses your fields and methods.
The private
access modifier, on the other hand, doesn't allow modification or even access to anything outside of the class or method. If you have a sensitive variable (such as the address of a house) that you don't want external classes changing, private
is the modifier for the job.
public
and private
can also be used on classes themselves to much the same effect. This is useful alongside inheritance, which you'll take a look at in the next lesson.
At this point, you might be thinking that that getAddress
method seems kind of silly. Wouldn't it be easier to just make the address
variable public?
This encapsulation method is like creating a protective shield (or capsule) around our variables. If we decided to make address
public, anyone with access to a House
could modify them. But by making a private
variable and then allowing access through a method, it's available to everyone, but only the House
class can modify it.
Something similar to encapsulation is the final
access modifier. A variable that's marked with final
can only be assigned a value once. Trying to change a final
variable will throw an access error. This is super helpful for physical constants - you don't want to be changing the number of floors in a house willy-nilly!
The big difference between having a public final
field and encapsulation is that while they both restrict access, final
variables are completely immutable - even within its own class. For this reason, you'll see the use of encapsulation much more often.
So we've talked about how access modifiers like public
and private
can change how a field or method is accessible, but where they're written or defined also affects the accessibility. (from here on out, we're going to talk about accessibility as scope)
One example of scope that you might already be familiar with is method scope. If a variable is created within a method, it can't be accessed from outside that method. The fields of classes follow much the same principle. Scope is also affected by the static
keyword, but we'll get more into that later.
Let's hop back to the lack of a main
method in our class.
This
House
is not a complete program - rather, it's a series of instructions on how to make aHouse
object.
So, what is an object, and how do we make one from a class?
What if I told you you'd been using objects this whole time without even knowing it?
Take a look at the code below.
Immediately, you should see some similarities to something else you've been doing a lot of - creating String
variables. This is because String
is actually a class - and all of the String myString = "This is my String!";
variables you've created are objects. In turn, the methods you've been calling on String
s - like myString.length()
- are actually member methods of the String class. (int
and so forth are primitives, and not exactly objects, but we went over that earlier).
Here is an alternative way of defining a String
variable:
Put more concretely, an object is an instance of a class. They're like the houses made from that House
blueprint we talked about earlier. They're also tangible - in real life, you could reach out in touch one.
In our programming world, this means that you can call methods on them. All of your House
member methods must be called on an instance of the House
class (a House
object). Calling House.getAddress()
would result in an error, just like how calling String.length()
isn't useful.
However, Java has an exception to this. If we wanted to make a method that is allowed to be called on the class itself, we would use the static
keyword:
If we know that getAddress()
is always going to return "1600 Pennsylvania Avenue"
, then why should we have to construct a full object?
It's important to note that if we tried to access address
in this static method it would result in an error, because there's no way to access member variables (fields) from static methods. However, you can access static member variables:
The key takeaway here is that we can only access variables and methods on an object, unless they are static
.
A keen reader might have noticed that public House(String shade)
does not specify a return type. This is not a syntax error - it's a special type of member method, called a constructor. It is called whenever we make an instance (a new object) of this class. Each object must be instantiated using the new
keyword before the constructor.
In this case, we're passing "white"
to the constructor, which takes it and sets the color
variable to it. This is a good example of when to not use static methods - if we attempted to call getColor
without having constructed an object, our House
class wouldn't have a color to return to us.
The constructor's power comes from letting us create different objects from the same class. In the blueprint metaphor, this is like being able to create multiple different colored houses from the same blueprint.
That was a lot. Classes and objects take some time and practice to fully understand, so don't be shy to refer back to this lesson.