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.
In the previous lecture, we get a brief taste of what classes and objects are and discuss the three primary principles of object oriented programming. In this lecture we will discuss encapsulation, which is one of the three primary principles of object oriented programming or OOP. Encapsulation again refers to the uniting of behaviors and data in a single entity called the object. There are multiple advantages that encapsulation gives us, specifically in terms of security and portability. In terms of security, encapsulation promotes so-called information or implementation hiding with the data or implementations inside the object is protected from unauthorized access from the outside world.
In terms of portability, we gain the advantage of being able to combine various data and behaviors into a single entity and move that entity, the object around without having all the different parts spread all over the place. To demonstrate encapsulation, we must first create a class. A class acts like a blueprint or schematic for an object. You might think of an architectural diagram for a style of a house and the actual physical houses that can be made from that diagram. So, in that case the diagram is like the class and the actual house is created from the diagram or like the objects. Let's dive into creating a class and then swing back and explain the features in more detail.
First, in our Section-7-Projects IntelliJ project, let's create a couple different files. We are first going to create a house.java file and then a houseDemo.java file. So, let's right click here. We're going to go to 'New', 'Java Class' and we will call this one house and then we are going to make another one, if we right click 'New', 'Java Class' and then we're going to have HouseDemo. All right, so for HouseDemo, I'm going to set this up public static void main(String args) and I just put that just so we know what we're dealing with. So, end of house demo there and then right here is our House class in this and house. House will not contain a main as you can see.
So, we will use HouseDemo to house our program's entry point, the main method. We intend on making different instances of the House class, that is different house objects using this class as a template. So, we've got the House class right here. I'll bring it down just a little so I can focus in on this. So, the data at the class level are called fields. Specifically, since each House gets its own instance or its own copy rather, we call these instance fields. So, private int numStories, private int numWindows and private String color. So, those are fields, F-I-E-L-D-S, fields, and specifically instance fields because every house object we create will have their own copy. So, let's write some methods, public int get numStories. This will return the numStories. Notice that the methods we have here don't have the static keyword on them like the main method that we used earlier and also other methods in the class with main. Why? Because these are instance methods and you will call them on an object so they refer to a specific object just like our instance fields do not the entire class. We'll see a little bit more about that in just a bit.
So, let's write some of these other ones out here. We've got public void set numStories. So, there's our setter there, and we'll go over this in just a second so don't fret what I'm typing. We're going to put public int get numWindows, return the numWindows. Good. Public int set numWindows just like we have a set numStory and then we're going to have this.numWindows = numWindows. And of course public string getColor will return the color. And then we also have... set numWindows should be void. I'm sorry. The setters should be void and then these two getters, this getter and that getter are int. This getter right here is string because it's returning the color which is a string and then of course we have set color which takes the color as its parameter and then we're going to just say this.color = color. So, if we go up here just to talk a little bit about this. If we were to try to type something like this instead.
So, you might think, why do we have this in front of it. So, if you do numStories = numStories, what it thinks you're doing is you're taking this parameter here and setting it to itself so it will compile but there is actually some problems here because it's not really accomplishing what we want to have done. We would like our internal fields that each belong to these objects to be set to particular values. So, we have to use this parameter here and we have to say, "Hey, the parameter has the same name as the field. So, I have to overcome this with this keyword." So, the local code of the method can't see the field numStories if you just put numStories = numStories. That's called name shadowing. So, we could pick a different name but coming up with twice the names for fields and then parameters gets difficult when you have a lot of fields. So, using the same name and the this keyword can overcome the name shadowing. This is a keyword that acts as a reference variable to the specific object you are inside. So, if I have my house and your house, each of us have a different this variable that's automatically available to our own objects. So, why didn't we use this in getting numStories or getting numWindows any of those?
Well you can. I could put this in front of these as well and it would still work. But the fact is there's no parameter causing shadowing. So, there's no problem. It knows we're talking about the field. So, the field has longer lifespan than these parameters. The parameters are dead as soon as the methods done being called. The fields will live as long as the object lives. We could still use this, but it would be optional. Now let's write out the HouseDemo to actually test our House class. So, if I go over to HouseDemo. Let's write the code here, House myHouse = new House() and then House yourHouse = new House(). And we created two instances here of the House class named myHouse and yourHouse respectively. These objects each represent different houses.
Now, let's test out our setters and getters below. So, we're going to say myHouse.setnumStories. We will say that's got two stories in it, myHouse.setnumWindows, maybe that has six windows, myHouse.setcolor, well that's a string so we have to put double quotes around it, don't forget that. And then we'll set this stuff for yourHouse, yourHouse.setnumStories, we will keep it in the same order it doesn't really matter but keep consistent here. YourHouse.setnumWindows is 10 and then yourHouse.setcolor, that's a string, so we will put blue just like that. Pretty cool. Now let's pronounce some information about our houses here. We will say your house is and then I'll put yourHouse.getcolor right there, and I will put and has with spaces on either side inside the string, myHouse.getnumStories, stories and another plus. We will say myHouse.getnumWindows and then of course that many windows. And I want to print out the same stuff for yourHouse. Actually, this should be myHouse. I'm sorry, my house. So, I got my, I screwed this up all the way.
So, it should be myHouse that get color. myHouse that getting them windows and myHouse start getting them stories. Now I will copy this and paste it. You may be thinking of a better way to do this already and good for you. We'll talk about that in a minute. But for right now this will suffice. I'm going to copy yourHouse here and print the getnumWindows, getColor, getNumStories along with the other information about yourHouse. And I might also maybe put extra line in here or something. Just extra line. Let's test this out by running it. When we run it, we will have to make sure we run the file with the main method inside it since that's where the entry point is. The other class you'll notice, we don't have a main inside that. The whole purpose of this is to represent a house, the entity. This class's purpose is to house main primarily and to be an entry point for the application.
So, let's 'right click' there and go to 'Run HouseDemo.main' and we will get output. All right, there you go. My house is red and has 2 stories and 6 windows. Your house is blue and has 3 stories and 10 windows. Pretty cool. So, that's exactly what we expect. They each get their own copy of those variables. So, when we call those methods on them, the instance methods like 'getNumStories' or 'getNumWindows', it's only applied to the specific house we're talking about. So, when I say 'myHouse.getColor', it doesn't show me the color of your house, it shows me the color of my house because it's an instance method and the data it's returning are instance fields. Each object gets its own copy. Nice. So we can see that each of these objects maintain their own specific data. They are truly encapsulated fields and methods.
We can treat the objects like self contained entities because that's what they are. Therefore, this means we can pass them to methods and change or obtain their values and perform different calculations if they perform any on their own, specifically, to individual objects and that's very powerful. Another note about terminology related to classes, the methods that set an internal value of the object are called mutators. A method that only gets data from an object like our getters here are called Accessors sometimes called an Observer. And again they're called Setters and Getters respectively, that's a very common term for them. You might be wondering now if maybe there's a quicker way to initialize the fields and objects without having to call all of the setter methods like we did here. I mean they're great if you have to update a value later on. But for initialization they're a little bit of a pain. A little clunky.
But thankfully the answer is, yes. There's a special method that is called automatically when an object of a class is created. It's called the constructor. Constructors have the same name as their class. If you don't write any constructors, the compiler actually provide you with one with no arguments called the default constructor. But as soon as you write a constructor, a no arg constructor or any other kind, the compiler no longer provides you with one. Let's update the code a bit and see what it looks like. So, if we go over to 'House' over here, inside here it's customary to put the constructors at the top here. 'NumStories' is 1. 'NumWindows' is 4 and 'Color' is gray.
So, this right here is called the no arg or no argument constructor. Some developers call this a default constructor but technically the Default Constructor is the no arg constructor that's provided by the compiler or if you don't provide any constructors so I would just call this a no arg constructor. So, this is a no arg constructor. And I'll put an end here just to say in constructor. Sometimes you'll see the words ctor, letters ctor rather, it stands for constructor. Now, here's a 'parameterized constructor', 'public House'. This takes 'int NumStories', 'int NumWindows' and 'String color'. This is the 'param ctor'. This one we'll just put 'this.NumStories = numStories', 'this.NumWindows = numWindows', and 'this.Color = color'. So, note that we could have technically just called the setters directly if we wanted to but this is just as efficient and there's only a couple of them, so we're pretty happy.
So, of course, we want to update 'HouseDemo' too. So, inside of 'HouseDemo', we have 'myHouse' which is up here, and we have 'yourHouse'. For yourHouse, I'm actually going to do a little bit of update here. So, 'yourHouse' I set with 3, 10, and blue. I'm going to comment that out because I'm going to take care of it up here. Since the constructor with three arguments that expects three arguments looks like this and we're doing overcoming name shadowing doing this. So, the three arguments; 'NumStories', 'NumWindows', and 'color', instead of calling all these setters, I'm just going to pass it in this way. 3, 10 ,and the string blue and that corresponds to each of the parameters just like any other method. These arguments will fill this parameter and then this parameter will give its value to the fields that we have up there. Pretty cool.
So, let's run it again to make sure we get the same behavior because I commented out these and we're just testing to make sure that the constructor works correctly. So, 'Right click', 'Run' and there we go. 2 stories 6 windows because our old one or 'myHouse' stayed the same. 'yourHouse' we updated it but it's the exact same thing; blue, 3 stories, and 10 windows. Great work, everyone. It looks like the constructors are working just great. Our parameterized constructor is setting the 'yourHouse' to have 3 stories, 10 windows, and the color blue as its color. Before we move on though, I'd like to issue you a challenge. Using our same set of files, 'House' in 'HouseDemo', create a static method in 'HouseDemo' named printHouseData, that takes a house object reference as a parameter and prints out the color, number of stories, and number of windows like we do in our Main. But then, I want you to replace the data we have manually printed out inside of Main with the calls to the methods on the two different house objects. Because we actually did a copy and paste on these little prints here and we don't really need that. We could actually just make this nice little static method to help us out and we won't have to have these right here.
So, this challenge involves re-factoring our current code to make it better by creating a method to promote reusability. Just like we learned about with methods. And you can change the wording of the printouts to be more general. For example, by saying theHouse instead of myHouse or yourHouse. So, pause the video and give it your best shot. Come back when you're done or if you need some help. How did that work out for you? Were you able to complete the challenge? I hope so. But even if you weren't, we'll do it right here. So, inside of Main, what we're going to do, we don't have to modify the House file. We just have to modify the file with 'main' in a 'HouseDemo'. I am actually going to, you can comment out or delete these but I'll wait a second just because I'm going to use it to help me here. Down here I'm going to actually write our little method here. So, right there public static. It has to be static.
So, you can call it directly from 'main', which is also static, void printHouseData, and we pass a house to it. That's 'end of printHouseData'. All right. And I'm going to take what we were doing above. We'll do 'println' we'll say "The house is" and we'll say 'house.getColor'. And next line we'll say new line maybe and between we'll organize it a little differently 'nand has' and we'll say 'house.getNumStories', and here we go, '+' again. We'll put a 'Backslash' in again so it adds another new line. 'house.getNumWindows'. Nice. Now, up here, I can either delete or comment these out. I'll comment them out. We'll keep the code for posterity's sake. But what I'm going to do is I'm just going to up here simply call 'printHouseData' pass at 'myHouse' first and then 'printHouseData' and pass at 'yourHouse'. That's all we have to do, right? That is much better than having to type or even copy and paste a lot of this over again. And in fact, since we had a little bit of extra spacing between these, I'll put an additional print line there.
But three lines of code versus this many lines of code is quite nice and we just call upon this method when we need to. Pretty cool. It doesn't seem like we're getting that much, but if we had to call the method 100 times or 150 times or 1000 times you could then see why the copy and paste method would be very error prone and cause all kinds of problems. So, let's run this again just to make sure we're getting what we expect. 'HouseDemo' format is going to be a little bit different. Here we go. The house is red, has 2 stories and 6. We missed something. We're going to print out there we go, "Windows". Right? Okay, perfect. Let's do it again. See little errors here and there.
We just fix them by acknowledging and realizing what the error was and then we just go in and fix the code. So the house is red has 2 stories and 6 windows. And then the other house, yourHouse, the house is blue has 3 stories and 10 windows. Great job. Now, you've learned about how to create your own class, including setters, getters and constructors as well as how to pass your own object references to methods. You have a lot of power now and I know this was a long lecture, so I'm really proud of you. In the next lecture, we'll work on a rectangle class to expand our knowledge about classes in general, and also solidify our knowledge of how static methods and fields are different from the instance methods and fields that we've looked at here. As a bonus, we'll learn about UML or Unified Modeling Language class diagrams that help us describe what classes look like. I'm very excited to get started. So, let's get going.
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.