What are objects?
Objects are structures which contain data in the form of fields and methods.
These fields and methods can be utilized in other classes by creating an object. Let's write a class that describes the fields and methods of a rectangle.
Then we'll write another class that creates instances of the rectangle class to find the total area of two rooms.
I've created this new class called Rectangle
and we're going to create some fields and methods inside of Rectangle
.
Now if we think of Rectangle
as not just a class, but as an object, we could come up with some different characteristics that a rectangle would have, as well as some actions that could be performed on a rectangle.
For example, a rectangle has a length and a width. So, we can declare these as global variables, or also known as fields.
package chapter6;
public class Rectangle {
private double length;
private double width;
}
Now that we have the fields of a rectangle, what are some actions that can be taken on these fields?
Well, we can calculate the perimeter of a rectangle. We can also calculate the area of a rectangle. So, the methods within an object perform actions.
Let's create those two methods:
public class Rectangle {
private double length;
private double width;
double calculatePerimeter(){
}
double calculateArea(){
}
}
Okay, so for the calculatePerimeter()
method, we need to return a double
.
So, we're going to calculate what's the perimeter based on the length and width, and we'll return that back.
The formula is 2 times the length plus 2 times the width.
double calculatePerimeter(){
return (2 * length) + (2 * width);
}
And for the area, the formula is simply length times width, so we can return that.
double calculateArea(){
return length * width;
}
This is a very simple class to represent an object.
package chapter6;
public class Rectangle {
private double length;
private double width;
public double calculatePerimeter(){
return (2 * length) + (2 * width);
}
public double calculateArea(){
return length * width;
}
}
Notice that this class does not have a main
method. We're not interested in executing any of the methods inside of this class itself. This class is made to be a general representation.
So, if I were to represent a general rectangle object, what would that look like?
Well, it would have the length and the width. And you'd be able to calculate the perimeter and the area. This blueprint is meant to be a generalized shell that we can then later on, in other classes, make more specific.
Before we do that, let's talk about some of the other components of a class.
We have the fields and we have the methods. However, we have no values for these. For example, if someone were to call this calculatePerimeter()
method, we have no idea what the value of length
is or the value of width
.
So, we have to provide some methods that will allow whoever's using the Rectangle
class as an object to set the length and the width to what it is that they want it to be. There are a couple of ways that we go about doing this.
One is to provide getter and setter methods for each of the fields.
We can create a method that will allow anyone who wants to use a Rectangle
object to set the length or get it if they want to read it, as well as the width.
I'm going to make a couple of more methods here.
This will simply return the length
double getLength(){
return length;
}
And this one will take in a parameter, we'll call this length
, as well.
void setLength(double length){
}
Now remember, we learned in the last chapter about the scope. So, this length
is not the same as this length
.
However, we want to set whatever value is being stored in the length
being passed to setLength
to this length
that belongs to the class.
So, we can use this keyword, this
:
void setLength(double length){
this.length = length;
}
The this
keyword refers to this class.
It's essentially saying to take the value of our local variable length
and assign it to our global one.
Now again, we learned in the last chapter that as these things map, they do not have to be the same name. We could have very well have called this “l”, and that will work as well. But, it's a good practice to name them appropriately. And length
is an appropriate name as long as you understand scope.
Let's now make getter and setter methods for the width.
So again, if you're asking to get the width, we're just going to return width
. And if you want to set it, we'll take in a width. And we say this class's version of width
should be equal to the width
that was just passed to us.
double getWidth(){
return width;
}
void setWidth(double width){
this.width = width;
}
Now you might ask, "Well, Angie, why do we use this.width
in setWidth()
but not in getWidth()
?"
The reason we had to use this.width
in setWidth()
is because of the scope. If we were to just say width
right here (without the this.
, it would think we were still talking about the width
that's within our local scope. Essentially, we would be setting the same thing equal to each other. But this is not the variable that we are talking about. We're talking about the global one in that case. So, we use the this
to specify exactly which of these we're talking about.
Okay, so getter and setter methods — that's one way that people who create the Rectangle
object can set these values. But there's also another way that's called a constructor.
All objects have a constructor. So, let's talk about a couple of these.
The very first type of constructor is the default constructor.
Constructors start with an access modifier, so we'll say public
.
And then, there's no return type, because they're not a method, even though they kind of act like one. And then you follow this with the name of the constructor.
The constructor's name must be the exact same name as the class.
So, this must be called Rectangle
. We follow with a set of parentheses that can optionally have a list of parameters, and then a body.
public Rectangle(){
}
Default Constructors
The default constructor is known as such because it does not have a parameter list. This means if someone wanted to create a Rectangle
object and they did not want to set the length or width just yet, then they can use this constructor without passing anything. And the default constructor is typically used to assign default values to the fields.
So, in this case we can say the length is 0 and the width is 0.
public Rectangle(){
length = 0;
width = 0;
}
So, we're giving these fields default values.
Constructors are used to initialize an object, or set up its state in some way. So, if they were to call us without setting anything, we would just go ahead and set these equal to 0.
Why don't we have to use the this
word here?
Well, we don't have to because we don't have a variable in this scope called length
or width
. So, it's very clear that we're talking about the global ones from the class.
Using Multiple Constructors
You can have however many constructors you want. All of their names must be exactly as the class name. What differs is the parameters that they accept.
Let's create another constructor for people who would like to create a Rectangle
and they actually do know the length and the width.
This time we can say, go ahead and pass us a length and pass us a width, and we'll set those values for you.
public Rectangle(double length, double width){
this.length = length;
}
We're using this
because we have two variables here called length
— one for the local scope, and one for the global scope.
Or, we can simply call this method setLength
, which does the exact same thing. So, let's do that.
public Rectangle(double length, double width){
setLength(length);
setWidth(width);
}
As a matter of fact, I want to leave this as this.length
, just so I can demonstrate to you that you can use either one.
public Rectangle(double length, double width){
this.length = length; //can be set this way
setWidth(width); //or can be set this way. these are only different here to demo alternative options
}
Another thing about classes is that they should practice encapsulation.
What is Encapsulation?
Encapsulation is one of the key principles of object-oriented programming. It specifies that the data (fields) of a class should be private and the methods (behaviour) of the class can be exposed (public) to other classes to use.
So, we've seen public
before, now we're introducing private
.
public class Rectangle {
private double length;
private double width;
No other code outside of this class can access things that are marked as private
.
So, no class can directly access the length
field, nor can they directly access width
. That's what the getters, setters, and constructors are for - to allow this class itself to determine how these fields get set and how they are accessed.
In order for these methods to be called, however, they must have an access modifier.
Right now, with no access modifier, only classes within the same package (chapter6
) can access these methods.
If we wanted classes that were outside of this package to be able to access these methods, we would need to make these public
. So, encapsulation says to make your fields private
and make your methods that are used to access those fields public
.
So, let's do that.
package chapter6;
public class Rectangle {
private double length;
private double width;
public Rectangle(){
length = 0;
width = 0;
}
public Rectangle(double length, double width){
this.length = length; //can be set this way
setWidth(width); //or can be set this way. these are only different here to demo alternative options
}
public double getLength(){
return length;
}
public void setLength(double length){
this.length = length;
}
public double getWidth(){
return width;
}
public void setWidth(double width){
this.width = width;
}
public double calculatePerimeter(){
return (2 * length) + (2 * width);
}
public double calculateArea(){
return length * width;
}
}
Now these last two methods (for the calculations) are not to necessarily access the fields. However, they would need to be called from outside of the package. So, we can make these public
as well. Notice in both of these, they do not accept any parameters.
Why not? Because they're going to use the fields that already belong to this class.
So, when I create Rectangle
object, if I already give you the length and the width when calling the constructor, then you'd know what those values are, and you can go ahead and utilize them.
So, we've looked at private
and we've looked at public
. There's another one that's called protected
.
If anything is marked as protected
, it means that other classes within this same package can access it. It's similar to having no access modifier at all.
Okay, so this class is a representation - a blueprint - of a rectangle. In the next section, we’ll make another class that utilizes this object to see this in action.