Classes and Objects
The course is part of this learning path
This course looks at Object-Oriented programming in Java and shows how classes are designed and constructed, and how objects are created from them. Then, we'll complete three projects: creating a bank account class, an ice cream class, and a circle class, as well as tests to make sure that they work in order to reinforce what you've learned.
- Beginner coders or anyone new to Java
- Experienced Java programmers who want to maintain their Java knowledge
- Developers looking to upskill for a project or career change
- College students and anyone else studying Java
This is a beginner-level course and can be taken by anyone with an interest in learning about Java.
So far in this section, we've learned a lot about the syntax and concepts used with classes and objects. We've learned about fields, methods and about the special methods called constructors that are executed automatically when an object is created. As a quick review, say the names of the three primary principles of object-oriented programming out loud. So, what are they?
That's right. Encapsulation, inheritance, and polymorphism. Good job. Repeat those multiple times as you begin and end your studies each day until you remember them easily. We have focused heavily on encapsulation, where we combine data and behaviors, which in Java take the form of fields and methods respectively.
Fields and methods are tied together in single entities called objects. And we use classes as the blueprint for those objects. In this lecture, we will continue practicing our newfound skills with creating and using classes as well as expanding upon what we've learned. In this lecture, we're going to take what we've learned and apply it to the construction of a Rectangle class. First, let's consider what we need to represent a Rectangle. What you see right now is a UML class diagram. UML stands for Unified Modeling Language. There are a wide variety of UML diagrams used to help software engineers to plan and design software as part of the software process. And they are not specific to Java.
The word model seems very technical, but it's not anything difficult to understand. A model is in essence a simplified version of whatever we're trying to represent. UML help software developers with the modeling process. UML class diagrams are an extremely popular tool used by many software developers who want to create different classes or design a system in which there are many interacting classes. Sometimes, you may even have a software team leader give you a set of UML class diagrams and some additional information and expect you to code it in a particular language such as Java. UML class diagrams are divided into three sections. At the top of the UML diagram, we have the name of the class. In the middle section, you list any of the fields
and in the bottom section, you list the methods. Remember that UML class diagrams use their own syntax and that this syntax doesn't match Java exactly. For example, the identifiers always come first and they're followed by a colon, followed by the data types or return types of fields or methods. You might have also noticed that the parameters are listed in the identifier : data type order as well. Also notice the - and + symbols in front of the identifiers. The two fields, length and width are both private. So, that's why there's a - symbol in front of those.
The methods are all public. So, that's why they have a + sign in front of them. Any private members of a class cannot be accessed outside the class. So, that provides a degree of protection in our case for the private fields of our Rectangle. Public methods on the other hand are accessible outside of the class. So, we can call them inside main as we need them. Make a note that the data always goes in the middle section and the methods always go in the bottom section. Their access modifiers such as public or private do not affect this aspect of the UML class diagram. Also notice that there's a field numRectangles and a method getNumRectangles() that are underlined.
This is because they are static. This means that they belong to the class, not individual objects. The practical implication is that you can access a public static method using the class name even if no objects of the type exist. Also, all of the rectangle objects will share the same value for numRectangles. The other methods and fields are instance methods and fields because every individual object contains its own length and width for example. And when you call getLength(), it's called on a specific Rectangle object. Now, taking what we now know about the Rectangle class from the UML class diagram, let's write the appropriate code.
First, let's create two new files, Rectangle.java and RectangleDemo.java. So, over here, Rectangle and then I'm going to create RectangleDemo. There we go. RectangleDemo will have main in it. Here. we go. And for the Rectangle class, over here. So, we have the private double length, private double width and then I'm going to separate this out a little bit. There's our private static int numRectangles. So, numRectangles again is a static field. Therefore, it exists when even no objects of the rectangle class exist and it is shared by all Rectangle objects when they do exist. Now a constructor. So, we could do length equals one and width equals one,
but I'm actually going to do something a little bit different, which I'll show you in a second. Okay. This one this.length equals whatever the length is passed in, this.width equals whatever the width is that's passed in for this constructor. So, this is one of the constructors and here's the no-arg constructor. All right. Now, since I've already got this one implemented and it does the work we want, we can set the length and the width to one to make the Rectangle the unit square. We'll say that's what we want the default behavior to be. So, notice though that we can use the "this" keyword but as a method call.
So, it's very versatile. And we're going to put one. I guess 1.0 probably makes more sense, doesn't it? Rather than one. It would still work but those are doubles. So, 1.0 and since we're using it as a method call, it recognizes this as another constructor. Pretty cool. So, the rest of the things that we're going to do, public double getLength() return length right there. All right. Now, getWidth() and now the setters. Here we go. Great. Now, the area method that we're about to write performs a calculation returning the area of the rectangle, of course. You might wonder why don't we just have a field for the area. Why are we using a method to calculate it? Well, we'll talk about that in a second.
So, public double area() and of course, that's length times width. So, back to why don't we just have a field for this? Well, the answer is we could have a field, but having a field for a value that can be easily calculated from other fields like the area can be tends to increase the probability of our objects having what's called stale data. Meaning, that we'd have to be very careful to make sure the area is recalculated every time we change the length or the width, which is annoying to say the least and kind of inefficient in some ways. The next thing I'm going to write is our static method. So, there's our static method that can return our static field.
Now let's write our demo out. So, we'll create r1. This one we'll use the no-arg constructor. The length and the width will both be one. Now I could use doubles like 5.0, 10.0, but it will actually convert it. So, that will use the parameterized constructor directly. So, the length will be 5 and the width will be 10. Let's try this first Rectangle now watch here .getNumRectangles. Notice I'm calling it off of the class name, not a particular object. Pretty cool, right? Now I'm going to do something else here, Rectangle r3 and I'm not going to set it equal to anything yet. And then, we'll try this. Rectangle.getNumRectangles. So, before we move on, let's actually run this, see what we get. So, think about what you would get though.
So, how many rectangles should it say there are at this point right here? How many should it print out? And how many should it print out after r3 is declared? Okay, that might be a little bit of a trick question or maybe you figured it out. Let me run it. And it says there are 0, because we didn't implement it. So, let's go back here. A little bit of a mistake here. So, this is returning numRectangles, numRectangles will automatically get the value zero. But there's a little thing that we, as in, I forgot so numRectangles++. So, we want to increase the number of rectangles every time we call the constructor. We don't have to do it in both of them because since this one calls that one, this will get called to this will get executed rather.
So, the numRectangles ++, that will increase the number every time a rectangle gets created, every time the constructor is called. So, let's run it again. Little bug there. So, it says there's 2, by this point which you'd expect because there's 2 declared and initialized here. But why does it say there's 2 right here? Why does it say there's 2 and not 3? Because we've declared a variable capable of holding the address of a rectangle but we haven't created one yet. So down here, r3= new Rectangle. I will say (2.5, 4) something like that. And then, let's print it out. So, let's say after r3 instantiated, right, so then we create the instance. Rectangle.getNumRectangles() And of course, maybe just to round this off a little bit, let's test out the areas here.
Okay, let's run this. And let's see what we get. So, we get 2 and then 2, and then, after r3 is actually instantiated right here, it says 3. Because just declaring a variable of this type does not call the constructor. So, then we get the areas. So, the first rectangles area's 1 because it's (1, 1), right? Then we get 50 for the next rectangle. And then 10 for the final rectangle because it's (4, 2.5) One in the middle is (5, 10). So, those are all pretty convenient numbers, and they are super complicated. So, we can verify them pretty quickly, right? So, pretty nice. So, you see the results are probably what you expected. Note that we could also put in selection control statements to control what kind of values we allow the centers to accept, thereby protecting the private data. So, that is something we can do inside the Rectangle class. You can of course test out the getters and setters as well, if you'd like as a little side challenge.
But your real challenge for this lecture is this- I want you to add a perimeter method that uses a rectangle's length and width to calculate the perimeter of the rectangle. Recall that the perimeter of a rectangle is the sum of the measurements of the four sides of the rectangle. So, a quick formula might be something like, 2 * length + 2 * width. Don't forget to test it out on at least one of the Rectangle objects in main. So, pause the video come back when you're done or if you need some help. How did that go for you? Were you able to implement the perimeter method and test it successfully? Let's work on it together. So, inside of Rectangle class, let's add under, we'll put it right under area, doesn't really matter, public double_perimeter(), return 2 * length + 2 * width.
And of course, let's call it inside of the demo file. We'll just call it on r1 just to test it, but we could call it on all three. Run this, there's our perimeter 4, which makes sense because if it's the unit rectangle or unit square, so we'd have one on one side, one on another, one on the bottom side, one on the left, so that would be they would add up to 4. Great job. You've done a lot of work in this lecture. In the next lecture though, we'll once again create another class to help solidify what we've learned. This time we'll create a Book class with no setter methods, only getters. Making our first immutable class. I'll see you there.
John has a Ph.D. in Computer Science and is a professional software engineer and consultant, as well as a computer science university professor and department chair.