Hello and welcome to this new lesson on Java interfaces. The purpose of Java interfaces is to let us unify common behavior. Let me give you an example of what I mean with common behavior. Here, I have a sample program that draws a delightful suburban scene with houses, and dogs and we'll add other suburban items to the mix soon enough. Let's look at the code. We have a list of houses, we add a couple of houses. We have a list of dogs, we add a few dogs. Then we draw the houses and we draw the dogs. Now, we have to put the houses and the dogs into separate ArrayLists because they're objects of different types. I can't put a dog in an ArrayList of houses or a house into an ArrayList of dogs. Our suburban scene would not be complete without cars, so go ahead and add a few cars to our program. One for this house and the other two for the Mcmansion over here.
Here are the cars. Let's see how I did it? I simply added an ArrayList for cars. Put in the cars at the coordinates that the question asked for, and then I added a third loop to draw all the cars. Now, this is not so pretty. And it really would be nice if we could some how unify all of these various elements, put them in a single container and draw them in a single loop. That's what we'll be able to do with Java interface types.
In Java you can use an interface type to describe common behavior. In our example, what do cars and dogs and houses have in common, they're all drawable. They all have a draw method. In Java, we use the interface keyword instead of the class keyword. To define interfaces. Here we say that Drawable is an interface, with a draw method. We give no implementation of the draw method, that's up to the individual classes, that implement this interface. Methods in an interface are automatically public. You can write the keyword public, or you can omit it. Now an interface is different from a class, an interface only specifies the behavior and you can't create objects of an interface, instead you create objects of classes that implement the interface, let's look at that next.
When you have an interface, and you have classes that can make use of it, those classes need to implement it. Here's how that works in Java. The class, declares that it implements, the Drawable interface. It provides a draw method, and then it also needs to put in some implementation. The class is free to provide other methods that have nothing to do with the interface. You can have as many classes as you like that implement the particular interface. Here the Dog class does the same.
Now, suppose you have an object of a class that implements the drawable interface. For example, a house, then you can save it in a variable whose type is the interface. And that intuitively makes sense, a house, is a kind of drawable. Now that solves our problem. because similarly, we can make an ArrayList of drawables, and this ArrayList now can hold dogs, houses, whatever. You simply take any object of any class that implements the drawable interface, and you add it to the ArrayList. It works, because you can convert from a dog, to a drawable which is what this ArrayList holds. In our same class, we can replace these three ArrayLists with a single one, an ArrayList of drawable. Go ahead and do that. When you're done, you should have just one ArrayList into which you add three cars, two houses, and three dogs. And down here, you should have just one loop. Of course, you also need to make sure that the car, house, and dog classes all implement the drawable interface.
Let me show you my solution. First of all, notice in BlueJ, that the dog, house, and car class, implement a drawable interface. You see that with these little arrows with a triangle on the end. If we open up one of them then we'll see the implements class over here. Now let's look at the scene class. Note that we now have a single ArrayList, everything gets added to that one ArrayList and we just have one loop. So you can see how interfaces dramatically simplified this program. What made it all work? The fact that you can convert from an object of a class to the interface type. In this case drawable. And so all these elements were convertible to drawable and then to draw them we can invoke the draw method on each element. We know they all have a draw method because they're all drawables. Sara has a few exercises prepared to make sure that you understand when you can and when you can't convert between two types. And then, she will show you a new interface that expresses when an item is likable in a social network.
That was a lot of new information, let's take some time to digest it before moving on. What will happen if I tried to declare a variable house of type house and then create a new dog and try to put that into the variable house. Will, the program declare a variable of type house and store a new dog in it. Will we get an error in compatible types because dog is not a kind of house? Or will we get an error dog is abstract cannot be instantiated?
The answer is Error: incompatible types. A Dog is not a kind of House. If you try to store a Dog in a variable that's made to hold a House, you'll get a compile time error, which is good. If Java let you store a Dog in a House variable, you might then try to call House methods on the Dog. And the Dog wouldn't know how to do them. Getting this error is actually a good thing. It means that java is helping us. This is one of the things that we were talking about when we mentioned really early on that java is a safe language. If java let you create a Dog and then store it as a House, you might try to live in it later and fail. But instead of doing that, the compiler will immediately tell you that there's something wrong with your code. Other languages might allow you to keep running the code, and then mysteriously fail or return the wrong results. This third option isn't quite what we want. This the area that you would get if Dog were an interface. If you tried to make a new Drawable, then you would get an error like this. Error Drawable is abstract cannot be instantiated. The Drawable interface has methods sort of, but it doesn't have enough detail about them for Java to actually make an object Drawable for you.
There's also something wrong with this declaration. Why won't this declaration work? You can't assign an object of a class to a variable of an interface type. You can't construct an interface type. Or you can't assign an object of a class to a variable of an interface type the object's class doesn't implement.
The answer is, you can't construct an interface type. We know this can't be the answer because we have assigned objects of certain classes to variables of interface types. In the example before this, you saw code that created new dogs and then put them in drawable variable or added them to lists of drawable items. So this statement is false. This statement is true, but doesn't apply in this case. I can only put an object into a variable with an interface type if the object is of a class that implements the interface. Like in this case. But if the dog class didn't implement the drawable interface, I wouldn't be able to do this. If you're not quite sure why you can't construct an interface type, let's look at the code. This is the code for a dog. It has all of the information on how to move and how to draw. The drawable interface has almost no information at all. If you tried to make a new drawable, it would know that it should know how to draw. But wouldn't know how to draw. That's why Java won't let you construct a drawable.
Let's do one more of these, what if I tried to declare a drawable that's a new rectangle what's wrong with this deceleration, you can't assign an object of a class to a variable of an interface type. You can't assign a value of an interface type to a variable of a class type or you can't assign an object of a class to a variable of an interface type the object's class does not implement
The answer is, you can't assign an object of a class to a variable of an interface type the object's class does not implement. We've seen that it's possible to assign an object of a class to a variable of an interface type. And this declaration isn't trying to assign a value of an interface type to a variable of a class type. We can create a rectangle without too much trouble, but rectangle doesn't implement drawable. So we can't store the rectangle that we created in a variable of type drawable. This is a little bit weird, since the rectangle actually does have a draw method, and the drawable interface promises that it will have a draw method and nothing else. The problem is that rectangle doesn't say that it implements drawable. For all Java knows, these two drawable methods could be completely different. If we wanted to save a rectangle in a drawable variable, we would need to change the rectangle class to say that it implements drawable.
Now Sarah has shown you another example of a interface, and I hope you've become more familiar with how they work. They're really pretty natural. But when you think about it, there is something mysterious going on. In our suburban scene, we had an array list of drawables. Houses, cars, dogs and so on. We got one of them, store it in a variable of type drawable, of course, then call the draw method on it. That has [UNKNOWN] d belongs to the drawable type, and drawable has the draw method. What's d? It's the variable, so it holds a reference to an object. An object of what class? You might think it's an object of class drawable. Now wait a minute, there is no class drawable. Drawable is an interface. So that can't be it, and in fact, there is no way of knowing to which class this object belongs. There is only one thing that we know about it, this object belongs to some class that has a draw method. And in fact as you loop over the various elements in the array list, this line of code may call different methods. The draw method of the house class, the dog class, or of some other class, so far unimagined, that also chooses to implement the drawable interface. This variation is called polymorphism, which is just a fancy word for saying different shapes. In our scene, that's a very appropriate name. Because the draw method can draw entirely different shapes depending on what the implementing class does. But the term polymorphism is used generally in Java to indicate any situation where you have a method call and the actual method called depends on the type of the object. Now, why is polymorphism important? It lets us build expandable systems, where we can add new types without having to change the essential logic of the program. I'd like you to try this out and add a new type to our suburban scene. Namely a ball class and simply the kind of ball you may find lying on the street. And when you do that, note how little of the program you have to change.
Here we have the red ball in the ball class. One has to do two things. First of all, the ball must implement the drawable interface. And we need to supply a draw method, in this case the method was very simple. It simply fills the circular shape. In the Scene class, we add a Ball, and that's it, nothing else needs to be changed. The mechanism that does the drawing stays completely the same. That's polymorphism in action. we have a general mechanism that can deal with any drawables. And if we want to add more, then we can simply add them without having to make any further changes.
Now our suburban scene was quaint, but it was rather static. Let's add a second interface to add some motion. The moveable interface has a method move, and we give the number of seconds for the simulated motion. Now, cars are moveable, our car class implements two interfaces, drawable, and movable. Lets see how that start. The car class now needs to implement the methods of both the drawable and the movable interface. Here is the draw method that we've always had, here is the move method we'll arbitrarily say that these cars moves at 10 pixel per second. And each of the components of the car is moved by that amount. What's it look like? When you run the program, you can see this car here moving. Later, we'll move the other cars as well, but for now please go ahead and move Fido as well.
So we wanted to make this dog move, simple enough. We simply make the dog move just the same as the car. But of course now we have to edit the dog class, and make the movement happen. There's the dog class. We add Moveable to the list of interfaces. And here's my move method. It's simply enough, I simply move both the picture of the dog and the name text. And I was asked to move it vertically at one pixel per second. That's why the horizontal displacement is zero and the vertical displacement is the same as the seconds. When you run the program, then here you can see the car move, and the dog move.
In the latest version of our suburban scene, we had a moving car and a moving dog. But of course really we want all the dogs and cars to move. One way of doing that would be, instead of just making one car and dog move, to put all the cars and dogs into an array list of movable objects. But you might say we already have an array list of drawables, can't we reuse that? We can, but we have to learn a bit more about working with types and Java. Let's say I have a drawable, what I'd like to know is if it's a movable. The instanceof test gives me the answer to that. This expression is true, if d happens to belong to a class that also implements the moveable interface. Of course in that case, I'd like to then call the move method. But not so fast, I can't call d.move because d is not movable. I have to convert d to something that is movable. Here is how you do that in Java. This expression means take d and cast it into a movable. We've previously seen the cast notation to change a floating point number into an integer, it's the same notation but now with an interface type. Once it is a movable, then it is saved in the variable of type movable. And then we can invoke the move method on m. Again you couldn't have invoked on d because d doesn't have a move method, that's drawable. This conversion is necessary. What if you make a cast of something that wasn't movable such as a house then he would get an exception and your program would terminate. That's why it's important that we first check whether d in fact is movable. These instances of tests and casts are not very common but they do happen every so often. And it's good to be familiar with them. So go ahead and put this to work. In the scene program, go through all of the drawables. Find out which of them are moveable, and move them.
Our task was to go through all of the elements and the list of the drawables, to check which ones are movable. That's done with the instance of operator. Now then we wanted to move them, but of course, we have convert them from drawables to moveables, that's done with this cast. Take the drawable, cast to moveable, save it in a moveable variable, and then we can use that variable to exercise the move method. When we run the program, we see the cars move, we see the dogs move, which is really isn't moving experience. Now, I'll turn it over to Sara, who will talk to you more about interfaces, the instance of operator and casting.
Casting with instance of checks is something you will occasionally need to use when programming in Java, but it's best to avoid it in general. Let's explore why. Here's the code for seeing.Java that you wrote before. What if we had accidentally forgotten to do this check and I just gone through all of the elements and tried to move them. What will happen if I run the program now? Feel free to try this yourself in BlueJ. Will the program run the same way? Will the houses move even though they should be stationary? Will there be a compile time error because drawables can't be cast to type movable? Or will there be a run time error? Because some drawables cannot be cast to type moveable. Like I said, if you're not sure feel free to try it out.
The answer is, there will be a runtime error, because some drawables can't be cast to type movable. If I compile and run the scene the way I did before, I'll get this drawing and this exception. ClassCastException, house cannot be cast to Movable. The program never got to the moving part. It looks like BlueJ has kindly taken me to the line where the ClassCastException happened. It looks like we tried to treat something like a moveable that was not actually moveable. And as you can see the program crashed completely.
It wasn't so bad that the program crashed in this case. I can just add the condition back, compile, and run again. And this only cost me a couple of minutes. But if I had been running this program for a whole day or something, and it had crashed and lost all my data. Or my website went down and I had to rush to my computer and run the program again to get it up and running. I would be pretty sad. If you find yourself casting something to an interface type and checking whether things are instances of other things. It's often a sign that you could design your code better, so that you could make the Java compiler do more work for you, and find errors at compile time instead of run time. So, what could we have done in this case? Maybe what we really wanted instead of a Moveable and a Drawable interface was some other interface, like Animated. Maybe Animated would have void draw As well as void move. And when houses implemented the move method, they could return immediately instead of actually moving. That way we could ask all of the animated elements to move And not worry about run-time errors. Or maybe we should accept that one ArrayList isn't enough here. Maybe we wanted two ArrayLists one Drawable and one Movable. There are lots of possibilities here, finding the best ones is something that you'll find by trying more things, keep practicing.
You've seen some interesting interfaces with drawable and likeable, but let me give you another very common reason why people like to use interfaces. And that is to be able to reuse an algorithm. Consider a common algorithm to compute an average. Here I have an array of countries, each of which has a name and an area. And I want to know, what is the average area of all of these countries. Now of course, I could write a loop to compute that, but lets say I want to a method that does this for any set of countries. So, I'd like you to complete this method that takes an array of countries. For each of them, find out what the area is simply by calling the Get Area method. Add up all those areas, and then return the average.
To compute the average, you first need to compute the sum using the algorithm from lesson seven, we traverse all elements in the array. Ask each of it for its area and sum them all up. Then we return the sum over the count, which is the sum over the length of the array. And as you can see here, I was a little nervous. What if someone gives me an array of length zero, then I don't want to divide by zero. So, I'm checking for that, and in the admittedly unlikely case that I do get an empty array, I return zero. When you run the program, It gives you an average area of about 75,000 square kilometers. That's actually not very large, it's a bit larger than West Virginia. Next, let's see how we can compute the average of another set of objects.
You've just computed the average area of a bunch of countries. Now, let's say, we have a different data set, a bunch of cars, and we'd like to know their average fuel efficiency. Again, I'd like to have a method average that does that, and the data class. And again, I'd like you to write that method.
Your task was to write the average method that computes the average of a bunch of fuel efficiencies. Now, of course that's almost exactly the same as computing the average of a bunch of areas. So let's copy and paste this code. And there are only two spots where I need to fix it up. Over here instead of country, it should say car. And over here instead of calling getArea, I should call getFuelEfficiency. And that's all. This is, of course, intensely boring, and there ought to be a better way.
You've just written the same algorithm twice, once for countries and then for cars. And you probably passionately wish to never again have to do that for any other class. So, let's see how we can come up with a generic way of computing averages. The trouble was that the cars and countries had different ways of measuring whatever it is that they wanted to be measured by. By with the car it was the fuel efficiency, with the country it was the area. But let's say they both agreed on what it meant for them to be measured. Let's say, they both implemented a common interface. I call this interface measurable. Let's look inside. It just has a single method, getMeasure. We expect each class that implements this interface to provide an appropriate implementation for getMeasure. For example, the country class implements getMeasure to return the area. The car class has the same method, return miles per gallon. Now, we can implement a single method in the data class that would take an array of measurable objects and it will compute the average measure. That's for you to complete. In the tester, we'll call this method, first on an array of countries, then we call the same method again on an array of cars. That's what I mean with the reuse, this method only has to be written once and we can call it with data sets containing objects of different classes. Now go ahead and complete the implementation of the average method.
Here is the method that you were asked to complete. We have an array of objects that are measurable. And we now should sum up all of the measures and then take the average. So over here, objects is an array of measurables. We need to give a type for each of its elements. While that type is measurable. Next we need to compute the sum of the measures. What method should we call an obj? We only have one choice. Obj is a measurable, and a measurable has only a single method called get measure. So let's call it. And here it is, our universal algorithm for computing averages. You'll never again have to write it, provided, of course, that the classes that you want to put in are willing to implement the measurable interfaces.
You've just seen a universal algorithm for computing the average of an array of objects of any type that is willing to implement the measurable interface. Let's implement another algorithm along the same lines. This time, we want to compute the largest element in an array. Again, we have an array of objects, and you may recall from lesson seven how to do this. You figure out what is the largest element that you've seen so far, at the beginning that's the first one. Then you go through the remainder of the array, if you find a larger one update largest so far. And at the end that's what you return. So go ahead and complete this method, it'll be the last time ever that you have to write it.
Here is how you complete the largest method. For simplicity, I'd put objects i and another variable that I call current. You don't strictly have to do that. And now I have to check whether current is bigger than largestSoFar. Well, they're objects so I can't compare them directly. I have to compare their measures. Is the measure of current bigger than the measure of the largest so far? If so, I changed my mind about who's the LargestSoFar. It's exactly the same algorithm that you've seen in lesson seven, now applied to measurable objects. Let's run the tester. And we see what the most fuel efficient car is. Not surprisingly, it's an electric one.
When you look at the code of the tester, there's something that's a little bit subtle. The largest method takes an array of measurable. Over here it returns a measurable, and I'm printing it here by adding it to the print statement. That only works because the Car class has a two-string method. That can convert a Car to a string. And it's a bit of a trick, the same thing won't work, for, computing the largest Country in a set of countries. Let's try that. Here, I'm computing, the largest Country of a set of countries. And now, let's run the program. and it prints the largest Country as some gibberish that's just what a string does by default on an object. And really what we want is we want the result of this call as a Country. We know it has to be a Country its one of the countries that came in so we want this to be a Country and not a measurable and here we want to be able to call The getName method on it. Now when you compile this, of course it doesn't work. We are told the types are incompatible. As a simple fix, go ahead and make that fit, and get this program to run.
So here was our problem. Data.largest returns a measurable. That's all it can return, because the data class knows nothing about countries. We need a country, and the answer is simply to cast. The cast is legitimate, the largest country had to be one of the countries that was put in, and its proof safe to convert back from a measurable to the country. Lets think once more what advantage we get from the measurable interface. When you look at the BlueJ, display of classes and the interfaces, you can clearly see that country and car both implement the measurable interface. You can see that the data class uses the measurable interface, that's the dotted line here. And what's important is that the data class knows absolutely nothing about country's cars or any other classes. It's decoupled from those classes, and that's what makes it, so generic. Now, Sarah will introduce you to an interface that's much more commonly used, a comparable interface.
Sometimes you don't have to implement an algorithm at all to reuse code. The Comparable Interface is a very common interface. And implementing comparable allows you to use handy pre-implemented algorithms for tasks like sorting. Here's the documentation for Comparable. It's an interface that has exactly one method, the compareTo method. Classes that implement the comparable interface promise that they will implement the compareTo method. When you call a.compareTo(b), it returns a negative number if a comes before b. It returns a positive number if a comes after b. And it returns zero is a and b are exactly equal. Once you implement the compareTo method, anyone coding can use it to figure out what the natural order of objects in your class is.
To give you an idea of how common this interface is, strings are already comparable. You can check whether a class implements comparable by looking at its documentation. Under all implemented interfaces, you can see that comparable is listed. Just to get you thinking, what will this method called return Badminton.compareTo Football. Will it return minus 4, 4, 0, true, or false? Think about the natural order of strings. And if you're not sure you can try it in bluejay. I haven't totally explained to you how to do this question, but just go with your gut.
The answer is minus four. Strings are sorted alphabetically, so strings that start with B, come before strings that start with F. Since badminton comes before football, compareTo returns a negative number in this case. compareTo could actually have returned any negative integer, and still been correct. But the way that compareTo is implemented for Strings, happens to return minus four.
Because strings are comparable, we can sort them by writing one line of code. If I create an array list of strings and add a whole bunch of things not in any order, and then I want to print them out in alphabetical order, I can add the line collections.sort strings. Collections is a class a little bit like a race that has some useful utility methods. If I compile and run this code, it will print out all of the animals that I added to the list, but from A to W. We might want to be able to sort countries like this too. Let's say countries are naturally ordered by their areas. Let's implement the compareTo method for countries. I want to be able to make an array of countries like this, and then use the sort method in the arrays class to sort all of the countries in the array, so that this will work. Let's implement the comparable method for countries. We'll need to make the country measurable and also comparable. Now the method should be public and return an int. It's called compareTo, and it takes an object, otherObject. Now if we want to compare otherObject to this object, the first thing we'll need to do is check whether otherObject actually has a name and an area. If otherObject is not a country, then it doesn't really make sense to compare it to this country. If you keep studying Java, you'll figure out how to avoid this cast using generics. For now though, let's focus on the compareTo method. For now, fill in the code, so that compareTo works as I described before for countries. Return a negative number if this country is smaller than other, positive is this country is larger, zero if the two countries are equal. And notice, I implemented .equals for you. So, you can use this. And if the countries are exactly the same size, you can break ties using the name. Can you fill in the rest for me?
Probably the easiest case would be when the two countries are exactly equal, so if this dot equals other country then I can immediately return zero, otherwise if this dot area is less than other country dot area I want to return a negative number, I will just go with minus one otherwise if this dot area is less than, I mean greater than OtherCountry.area, I want to return a positive number. I think one'll do. Otherwise their areas must be exactly equal, in which case, I'll use the string compareTo method on the name, and return the result of that. Once I fix my syntax errors, I want to check that this actually works the way I'd expect. So I'm going to get out my code pad. And make some new countries. El Salvador should come before Belize. So If I compare El Salvador to Belize, I should get a negative number. So far, so good. Certainly the opposite direction should be positive. And Belize compared to Belize should give me a zero. And just to make sure that I'm breaking ties, let's compare Belize to a made up country, with the exact same area. Alright, negative 11 sounds good to me. So long as compareTo doesn't return zero, with two countries that are clearly different countries. Now, to make sure the work wasn't all for nothing, I want to show you that now we can sort all of the Central American countries. Using the Arrays.sort method now if I run this, now I've tempered with the two string method a little bit just to make this easier to see, I get the countries in order by their areas, sorting is actually an interesting task, when many people have studied for years but we just managed to do it in one line of code array for interfaces.
We have been talking a lot of about interfaces and how useful they are, now I would like to bring up a related topic called inheritance, and interface specifies behavior that the class that implements it should exhibit. Inheritance can do a little better than that, when a class inherits from another class it picks up behavior and data. Here is an example of a set of classes, where one would probably use inheritance, to model them. We have a class vehicle, it's a very general class. A car is a special kind of a vehicle, a motorcycle is another kind of a vehicle, a truck is a kind of vehicle. And an SUV is a kind of car. Now you would use inheritance not interfaces in this situation because you could put common data into the vehicle class. Such as the weight of the vehicle, the number of wheels, things like that. Now you might say why not always use inheritance? It seems better. But there are two issues with it. One is, it is complex, and also a class can only inherit from one class, whereas a class can implement as many interfaces as it likes. A bit of terminology, the class from which one inherits is called the super-class, and the class that does the inheriting is called the sub-class. We would say truck is a sub-class of vehicle. Vehicle, has a super-class, of truck. Just to see that you're paying attention, let me ask you, what are the sub-classes of car? What are the super-classes of car, the sub-classes of SUV, and the super-classes of SUV, in our inheritance hierarchy over here? Just put your answers into these boxes.
Let's look at the car class. It's subclass is SUV. An SUV is a special kind of a car. At superclass is vehicle. A car is a special kind of vehicle. A vehicle is more general, a car is more specific. Subclasses of SUV, we don't have any. Superclass of SUV, car is a superclass. And then going one further up, vehicle, is also superclass, sometimes people say that car is a direct superclass. Now we could implement, this vehicle hierarchy in Java, but truth be told, it's a little dull, and we'll come up with a more interesting hierarchy.
And the car hierarchy you've just seen, makes it easy to understand the concepts of super and sub classes but it doesn't make for a very interesting implementation, instead lets look at quizzes. In a quiz, you can have different kinds of questions so it's natural to have a super class question. And then, you may have various sub classes. Maybe a question where you need to fill in a missing word, or a question where you're given a bunch of choices, or one where you've to supply a number, but it might be okay if it's not exactly the right answer. A numeric question might take round off into account. And so on. You could even think that there is a, sub-class of choice question. I'll call it a Multi Choice Question, you know, one of those where you need to supply all of the choices that are correct. What do our questions have in common? They all need to be able to display themselves, and the display may be as simple as showing the question text, or it might have to have a list of choices. Or an underscore at the right place for filling in a word, and also any question needs to be able to check its answer. That might be a string comparison or a number comparison that's, or a number comparison after some accuracy. So the idea is that, the super-class question will give reasonable implementations of these methods, and the sub-classes can modify them if they don't work for the context of the sub-classes. I've implemented the question class for you, and here is a programming problem that's designed to make you familiar with that class. So that you can form sub-classes, as we go, go along. Here's the question class. Have a look at it's methods, as you answer the next programming question. And here is a demo program, in which I want you to fill in some details. Make a question object, and then there is a method present question. That displays a question, gets the user response, checks whether was correct. They're methods for displaying and for checking a response. And I want you to look them up and call them.
There are two tasks for you. First off, to make a new question. Here, we construct the question, and now we need to set the question text. There's a method for that. And we need to set the desired answer, and there's a method for that. Really all you had to do is look up here and imitate how to set up the first question. In the present question method, we first display the question. Again, there is a method for that. To find that out, you actually had to look up the Question class, the method is here. There's no other way to show that question text than to call display. The code for reading the response was already given to you. Now, we need to check if it's the correct response. That's the job of the checkAnswer method that you also had to discover by looking at the code of the Question class. It gets the user's response and it returns true of false depending on whether it's correct or not. We were supposed to print true or false. The simplest way of doing that is to just print the value of the Boolean variable. But, of course you could also print true in this branch and false in this branch if you prefer. So if the outcome is true, we return a score of 1 otherwise a score of 0. Let's just run this program. So let's see. Who was the inventor of Java? Everyone knows that or not. And who was the founder of Udacity? Oh, I better get that one right or I'll get in trouble. Now, [LAUGH] I did this one right and at least I got a score of 1. So, now you have an idea on how the basic question class works. And we're ready to refine that class by forming sub-classes of it.
You've just worked with the question class and now its time to form a Subclass. We've all seen these multiple choice questions, as a question and there're multiple choices hence the name. By the way, if you ever want to know what's the original name of the Java language, it was Oak, which was a name that was so dull and boring that they changed it. Now, of course, one could put this entire text here into a question class and set the answer to this string three. But that too would be dull and boring. It would be better to have a class that specifically deals with multiple-choice questions. So that we could declare an object, somewhat like this. We make a Choice Question, that's what I'm calling this class. We still need to set the text of course, but then for the choices I want to be able to call a method that I call addChoice that adds the particular choice and then specifies whether it's false or true. When I formed the Choice Question class, I didn't want to start from scratch. I want to inherit as much as possible from the question class that's already written. Let's see how to do that. I'll define the ChoiceQuestion class and then I specify that it extends the question class, that's the Java keyword for denoting that ChoiseQuestion should become a subclass of question. Into the body of the subclass, I put in any new methods that are present in the subclass but not the super class. Such as the Add Choice Method. You also put in the implementations of any methods that needed to change in the sub class. For example, we'll need to change the display method, since displaying a choice question must also display the choices. And finally, you of course need to add any instance variables that the choice question class needs to do its job. In our case, that would be the list of the choices. The key point is what you don't put in here. When you define a subclass, you never include any of the methods from the superclass that work just fine. For example, the set text method will work fine, and we can simply inherit it from the superclass. Also, you don't want to include any fields from the superclass. You get those automatically, and if you were to include them again, you'd get 'em twice, which is not good. The point is that, what you put inside here is the difference from the superclass. Everything that the subclass has, that the superclass doesn't have at all or that it doesn't have in the same way. Let's have a closer look at exactly how that works for question and choice question. Here is our question class, here is the choice question class. Now have a close look and tell me, which methods does the choice question class inherit? Just give me the names of all those methods that choice question doesn't redefine, that it simply picks up from question. Which methods does choice question overrides? That is which method does choice question need to redefine because the one's from question are not satisfactory. And finally, which method or methods does choice question add that weren't present in the question class in the first place? Just give me the names of the methods, all together there are 5 of them.
Alright, here goes. There are three inherited methods, set text, set answer, and check answer. And you can tell because they are over here, and they're not over here. Because choice question extends question, it picks up all of those methods automatically. It inherits them. Display, on the other hand, is both here and here. Which tells us that the choice question was not happy with this display and provides its own. It overrides the one from the super class. Finally, there's add choice, which wasn't over here at all, so that's an added method that only appears in choice question, but not in question. Next, you'll get to implement these two methods, but the good part is, you don't have to implement these because they are already in the question class and choice question just inherits them.
Let's get started with implementing the missing methods in the subclass. We'll start with the addChoice method in the display method I've given you a stop gap implementation we'll refine that later. In the addChoice method we need to add the new choice one of the multiple choices somewhere where as some where. We actually also need to have an instance variable to collect the choices, we'll just collect them in an ArrayList of strings. One entry per choice that means you needed to clear that instance variable in the choice question class and you also need to initialize the instance variable in the constructor. Once you've done those things you can turn back to the addChoice method and simply add the choice. There's the second parameter that indicates whether the choice is correct or not. We'll take that one up in just a minute. At this stage, just leave it alone. So go ahead and do those three things and then we'll compare notes.
There're three things we have to do. First off, we need to declare an instance variable to hold the choices. That's an ArrayList of Strings. In the constructor, I initialized it with an empty ArrayList. And in the add-choice method, I simply add the choice to the ArrayList. That was a good start, but so far we've ignored this parameter that tells us whether that choice was correct or not. And that's what we're going to be doing in the next stage.
Lets continue implementing the addChoice method. You've already done the first part, adding a new choice to the list of choices, now if this parameter here says that it was the correct choice then we should set the answer, and the answer should be a string 1, 2, 3 or 4 depending on whether this was the first, second, third or fourth choice. How do you know which choice it was? It's not passed as a parameter to add choice, but you can tell by looking at how many elements are already in the choices array. Of course, when you ask the choices array for it's size, that's an integer, answers are strings, just concatenate with the empty string to change the integer to a string. And now you're going to have a bit of a challenge. When you have a choice question object, it has two instance variables. The correct answer, this instance variable is inherited from the question super class and the list of choices. You will want to set the answer to a string, such as this string 3, but how can you get at it? The answer is an instance variable of the question class and it's private, no one can access anything private in the question class accept the methods of the question class themselves. Choice question extends question but that doesn't give it any special privileges. It cannot access this instance field any more than anyone else. So that's the challenge you need to overcome. And the point is, of course, that just like everyone else, you will need to use the public interface off the question class. Go ahead, give it a try, and implement the add choice method.
Your task was to complete the implementation of the addChoice method, and the previous step you had added the choice string to the list of choices. Now we want to take this parameter into account. And if were handed the correct choice, we want to update the answer. Now the answer is the string, such as three if we're currently at the third choice. So, over here, we can find out what the current choice is by measuring the size of the choice array. When we're at the third choice, there are three choices in the array. The number that we need is three, but we need it as a string not as a number. That's the step here. Now, this is the string that we need to set as the answer of our question. I've talked about that, you cannot simply access the instance variable of the super class, but mercifully, we have a method from the super class that does just that, namely setAnswer. So, all we have to do is call setAnswer. SetAnswer by the way is an inherited method that we simply get to call. Alright. Now you've implemented your first subclass method completely. And next, we'll turn to implementing the display method.
Now, let's turn to the implementation of the display method. It's supposed to display a choice question in this format. First, the text of the question. Then all of the choices, and we put a 1, 2, 3, 4 in front of each of the choices in case the poor test taker is too frazzled to figure out the numbers themselves. It's easy enough to do this part. All we have to do is loop through the choices and print them with a number in front of them. And since this has nothing to do with learning about inheritance, I'm just going to give you this code. It's right here. So we print the number of the ith choice and the ith item. actually not quite because in Java the choices have indexes, zero, one, two, and three. And we chose the more traditional one, two, three, four, which accounts for the i plus 1 over here. The hard part is to display the text of the question. And again, the question text is in the Superclass object, and we can't get at it directly. Let's have a look at the Super class. Here is the question text, do we have any method that lets us read it? there is, And we could call display, and then it would print it. That's just what we need. Lets do it. Here I call display that should display the text and then here I am displaying these choices around the demo. Oh! something very bad happened, I got a StackOverflowError. Now, that's technical link of for having a method that keeps calling itself. why itself? See the method is called display and here it calls itself. That's a problem, I didn't want to call my own method, I wanted to call the display method of the Question class. So my difficulty is that I have two methods called display in the Superclass and in the Subclass. And they have the same name. That's exactly what always happens when you overwrite a method. Now, there's a special syntax for invoking the Superclass method and it looks like that. You simply say super.display. Go ahead and give that a try and fix up the display method.
We had the problem that simply calling display inside the display method couldn't possibly work, it would just call the method itself and itself, and itself. The way to get the super class method involved, which displays the question text, is simply to use the keyword super. This will work. Now the program correctly shows, first the text of the question and then the list of choices.
You've just implemented the choice question [UNKNOWN], and used it in a program that displayed two choice questions. Previously, you had written a program that presents two plain questions. Can we mix the two? How can we write a program that presents a plain question, and then a choice question? Should we provide two present question methods? One for questions, one for choice questions, or is it okay to provide a single present question method who's parameter has type question, and use that to present both the question and the choice question? Or should the parameter of that single method have type choice question? Or, are we trying the impossible? What do you think?
It's good enough to provide a single method present question whose parameter is a question. A choice question is a special kind of a question, and so, you can pass a choice question into a method that expects a question. In general, anytime that you have a subclass, you can give it to any method that expects a super class object. Go ahead and try this out. Make a quiz that contains a question and a choice question. Just reuse that question that we had before, that asks who was the inventor of Java. Over here, both of the questions are paths to the single presentQuestion method. And in that method, just to make sure that you got the point, fill in the right type for the parameter.
Here is the first question, I just copied it from a previous program. Here's the second question. Notice the first one is a, plain old question, the second one is a choice question. I'm passing both of them to the presentQuestion method. That's just one of those methods, it's down here, and its parameter has type Question. So it's okay to pass a choice question into a question parameter. You can always convert from the subclass to the super class.
You've just written a program that contains multiple question types. Over here, we have a plain question, over here a choice question. We pass each of them to the present question method, that method is down here. It has a parameter of type question. And now let's focus on this display method here. Notice that q is of type Question. And I would like you to tell me exactly which display method is called, in the call q.display. Is it always, the display of the question class? Is it always the display method of the choice question class? Does it vary? Is it sometimes question display and sometimes choice question display? Or could this call even call some other method, something other than question display and choice question display. Let me know what you think.
When you think about it, you know that this call here in your last program sometimes showed a question and sometimes a choice question. But actually, in other programs, this call could even show something else. We could have a third class that's also a subclass of questions. Pass it to present question. And then its display method would be called.
We've just talked about which display method gets called int present question method? The method has a parameter whose type is question. So here's the parameter variable. It contains an object reference which points to an object, an object of what type, while you think it's question, because that after all has the type of q, but not so fast, the type of q, the variable isn't the question. The type of the object is really not known. It could be any sub-type of question. Now the good thing is, that when the program runs it does the right thing. At runtime, it's determined what the exact type of this object is. And its display method is caught. That might be question.display, choice question display, or the display method of some other class. That also extends the question class, this is a very useful feature because it allows us to write generic codes such as present question that works with questions of any type and actually this diagram should be familiar to you, you've seen the same diagram when we talked about interfaces and there is the name for the fact that the correct version of a method Get selected at run time. Remember what that's called? Was it object already has programming? Incapsulation? Inheritance? Or Poly morphism?
The answer is polymorphism. Polymorphism means that a method call such as here the call to display reaches the correct method at run time depending on what this variable refers to, the correct version of display is fit. Polymorphism is great because it make systems extensible. I can add new classes to the system, such as new types of questions, and still reuse the present question method without having to change it.
We just saw that because of Polymorphism, one can write a program that can handle any mix of quiz questions. Let's try that out and develop another question type. A numeric question expects an answer from the user that is a number. For example here we ask what is the area of a circle with radius one. And the answer is of course pi, but that might be hard to enter, and we can't really expect the user to type in the exact value of pi, and as you know, this is not even the exact value, either. It goes on forever. We just want the user to be able to enter, say, 3.14 or 3.14159, depending on how well they remember those digits. Either one of those answers should be fine. In fact, we'll take any answer, that's up to point oh one away, from the answer, that the user provides. In a different numeric question we might use a different tolerance. Your task is to implement this new question type. We've give you the constructor, your job is to provide the set answer method. And the check answer method. And the check answer method, you need to take the tolerance into account, you need to check whether the given number is not too far away from the response. So, technically the response is a a string, you need to convert it to a number. And we show you here how to do that. You may need additional instance variables. And then you should put them here. Go ahead, give this a try.
Lets start with the most interesting method, in the checkAnswer method, I am given the response which is a string, I convert it to a number by calling DoubleparseDouble and now I check whether that number is close enough to the actual answer, we've learned in lesson four how to do that, we take the difference of the two numbers that you want to compare, take the absolute value. And check whether that's most the given tolerance. Now, there's just one catch. What's this answer here? Well, it's whatever was supplied in the set answer method. Interestingly, the set answer method here takes a double, so it's not a string. And that means it's different from the set answer method that was defined in the question class. That method took a string. Now I could've converted this number into a string, and then passed it on to the setAnswer method of the question class, and let the question store it as a string, and then I could've converted it back from a string to a number, I suppose, except when I tried that it didn't work, because the question class has no way of giving me back the answer. It's used inside it's own check answer method. But that one is worthless to me, because it doesn't take the tolerance into account. So instead, I just store the answer as a double in the numeric question.
You've just implemented a program that shows two kinds of question; a plain question and a numeric question. Both of them work past to the presentQuestion method. Clearly we can extend the system with all sorts of other question types, and we won't ever have to change the presentQuestion method. So, what polymorphism gives us is extensible software systems. We can start out with something simple and without having to change any of the basic structure. We can extend the functionality by adding more and more subclasses. Polymorphism is one of the two corner stones of object orientated programming. The other one is encapsulation. Remember that encapsulation means, we separate the interface of a class from it's implementation. And that means that the implementations can evolve over time and gain more functionality without having to change the rest of the system. So, both of these cornerstone properties let us build systems that start out small and that can be functional for a long time. Which is why object-oriented programming has become such a popular methodology for writing programs. Now, in a few short weeks, you have gone from just becoming familiar with objects and how they work, to being able to write quite sophisticated programs that can withstand the test of time. So, you've really come a long way in this introduction to programming, and I hope you enjoyed it.