This is Chapter 7 from my book, Learn to Program with Java. If you would like to buy the book, or find out more information on it, just follow this link
http://www.johnsmiley.com/mybooks/0072131896.htm
In Chapter 6, we began the process of learning how to introduce modularity into the programs we write by creating custom methods in our startup class module. Once defined, these methods were then 'called' from its main() method. In this chapter, we take modularity several steps further by creating what Java calls Instantiable classes--that is, classes from which objects can be created by another class, sometimes called a client program. Creating objects from classes is the name of the game in Object-oriented programming languages such as Java, and by the end of today's class you'll see why. The data and the code in your classes easier to work with, the number of lines of code in your startup class shrinks, and overall, your programs become easier to follow, maintain and modify. Plus, the code you place in Instantiable classes is available to be used by hundreds, even thousands, of other programmers in company or even throughout the world. This is truly object oriented programming.
"Early on in our course," I said, as I began our seventh class, "I mentioned to you that Java is an Object-Oriented programming language, in which in we work with standard packages of classes and objects that make the job of writing a program much easier. I also told you that at some point, you would be able to design classes of your own from which objects could be created. However, I warned you that it would be some time before you could do this. Well, today's the day. Up until now, we've used methods of objects created from classes provided to us in the standard Java packages---methods like the println() method of the System object, and the showInputDialog() method of the JOptionPane object. In today's class, you'll learn how to design and create classes from which you'll other classes will be able to 'instantiate' objects."
"Instantiate?" Rhonda asked.
"Instantiate is a term that means to create an object from a class," I said. "In Java, an Instantiable class is a model for an object, much like an architectural blue print is a model for a house or a building. Just like from one blue print, many 'instances' of a house can be built, from one Instantiable class, many instances of an object can be created. I know what you're probably thinking. The classes that we've created so far haven't been used like that. That's because they've been startup classes, which are classes intended to be executed from the command prompt. Instantiable classes are different. They are not intended to be run from the command prompt, in fact, they can't be. Instantiable classes are meant to enable other classes---mainly startup classes---to create objects from them. Today we'll learn how to create those Instantiable classes, and by the end of today's class, we'll have designed and coded several which will model real-world objects."
"This sounds exciting?" Ward said, "what kind of real-world objects can be modeled using Instantiable classes."
"In the real world of programming," I said, "Instantiable classes model employees, students, inventory, database records, to name a few. In today's class, we'll create an Instantiable class to model a bank transaction, and of course, we'll also be creating a class to model the English, Math and Science students here at the university."
"This process sounds to me like it may not be all that easy." Rhonda said.
"I don't want to make creating Instantiable classes sound too easy," I said, "but I think you'll find that it's just an extension of the modular programming process we learned about and practiced last week when we broke our code up into modules by creating custom methods. Creating Instantiable classes is a matter of determining what real-world objects need to be represented in your program, and in apportioning variables and methods to each one. In many ways, this is nearly complete with the Grades Calculation project. I think we all realize by now that the project is modeling a real-world student. In the Grades Calculation project, that's one object, and there may be more. The bottom line is that if you are comfortable with what we did last week concerning method creation, you'll have no trouble going through the mechanics of creating Instantiable classes. Experience will help you identify the objects you need to model in your program--along with the characteristics and behavior of that object you need to simulate as well."
"Do Instantiable classes look like startup classes," Peter asked.
"Startup classes require a main() method so that they can be executed from a command prompt," I said. "Instantiable classes do not contain a main() method, and for that reason, Instantiable classes can't be executed directly from a command prompt the way the programs we've written so far can. Instantiable classes are meant to provide their blueprint to other classes so that objects can be created from them. Instantiable classes are designed in such a way that the objects created from them simulate the characteristics and behavior of a real world object---such as an employee or a piece of inventory."
"What do you mean by characteristics of an object?" Blaine asked. "Can you give us an example of an object's characteristics"
"Yes I can Blaine," I said, "For instance, if we create an Instantiable class designed to represent a real world employee in a corporation, we would want to create a class capable of representing the employee's name, address, social security number, and salary, to name a few characteristics. The characteristics of the employee object are represented and stored 'inside' the object by the implementation of the Instance and Class variables I briefly mentioned last week."
"That makes sense to me," Linda said, "but what about an object's behavior that you mentioned? What kind of behavior can an object possess?"
"Well," I said, thinking for a moment, "an employee has certain kinds of behaviors---such as working on a particular task, attending meetings, traveling to a customer site, taking a vacation day--these kinds of behavior can be simulated in an object by the implementation of a class method, the kind that we wrote last week."
"I see," Kate said, "but wouldn't the code for that be pretty complex. I'd hate to hate to write it."
"You're right Kate," I said, "I bet that code would be pretty complex to write, but the beauty of Instantiable objects is that if you wanted to use an Employee object in one of your programs, you wouldn't have to write a bit of that code. It's the designer of the Employee class that needs to worry about the details of the code to model that behavior, and once it's written, it can be used over and over again by hundreds, even thousands of other programmers. You see, all of the really difficult code necessary to implement the behavior of the object resides within the class itself. A programmer who wants to use the Employee object—just like we've been using the System object to execute its println() method---only needs to execute the object's method in order to implement the behavior."
"So the programmer who designs the class from which an object is created isn't necessarily the programmer who will later use the object in a program?" Ward asked.
"That's right Ward," I said. "It's usually senior level programmers and designers who design the classes from which objects in a corporate environment are created. I know Java programmers who spend all of their time designing Instantiable classes just like that---and never write any code that actually creates any of those objects."
"So what happens after the Instantiable class is designed," Steve asked.
"Usually," I answered, "the class is placed in a package, advertised and made available to other programmers in the company or corporation. And if the Instantiable class you design is really good, it may be used by other programmers all over the world---just like the Java System object is."
"I think you mentioned this a minute ago, but I may have missed it," Mary said, "but if characteristics of an object is implemented via Class and Instance Variables, how is the behavior of an object implemented?"
"Behavior in an object is implemented via methods," I said, "just like the methods we wrote last week."
"I'm anxious to see one of these Instantiable classes," Linda said, "Can you show us one?"
"Sure thing Linda," I said, "Let's create an Instantiable class called Banner designed to display the user's favorite programming language in the Java Console. The class will contain just a single attributed called favoriteProgram, implemented via an Instance Variable, and it will possess just one kind of behavior, display, designed to display that single attributed. This behavior will be implemented via a method.
I then displayed this code on the classroom projector.
public class Banner {
String favoriteProgram;
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
NOTE
Class definitions that begin with keyword public must be stored in a file with the same name
"Where's the main() method?" Rhonda asked. "I don't see it anywhere."
"Instantiable classes aren't required to have a main() method," I said. "since they are not intended to be executed directly from a command prompt. Instantiable classes are meant to serve as blueprints for objects that are created from another class--we'll see that in a moment. Before we do that, however, let's take a closer look at the code in the Banner Instantiable class. The first line of the class looks just like the other classes we've seen so far. It begins with the public keyword, called a Class Modifier, followed by the name of the class…"
public class Banner {
"The keyword public in the class definition," I said, "is required so that objects of this class can be 'instantiated' or created from another class. We'll see how that happens in a few moments"
"That next line of code," Valerie said, "looks like a variable declaration—is that the Instance Variable you were telling us about?"
"That's right Valerie," I said. "An Instance Variable is a variable declared within a class, but not within any method of the class. The String Instance Variable favoriteProgram is used to implement the one and only attribute of the Banner class…"
String favoriteProgram;
"Let me make sure I understand why this is an Instance Variable?" Dave said. "It's the fact that the declaration does NOT appear within the display() method? Is that right? Otherwise, it appears to be an ordinary variable declaration to me."
"That's right Dave," I said, "Instance Variables are variables that are declared outside of any method. Instance Variables, by convention, appear at the 'top' of the class, just after the class name."
I waited to see if anyone any questions before continuing.
"Now let's take a look at the one and only behavior of the Banner class---display, which is implemented via a method…"
public void display()
{
System.out.println ("I love " + favoriteProgram);
}
"As I think you can see," I said, "this method is very much like the methods we learned to code last week. The display() method merely displays the value of the Instance Variable favoriteProgram to the Java Console using the println() method of the System object. Of course, what makes this special, is that it isn't code from the Banner class itself that will execute the display() method but code from another class which will first create an instance of the Banner object which will then execute this method."
"When you say a object is created from the Banner class," Dave said, "does that mean that each object gets its own copy of each of the Instance variables and methods to work with?"
"That's right Dave," I said. "Later on in today's class, we'll see that it's possible to create, in a program, more than one object from the same class. When that happens, each object has separate 'copies' of each of the Instance variables and methods defined in the class. In this way, there's no danger of one object 'stepping on the foot' of the other."
"Are we going to execute this class?" Rhonda asked. "I can't wait to see how this works."
"We can't directly execute this Banner class from the command prompt," I said, "Since it has no main() method, it can't be run directly from the command prompt. Remember, Instantiable classes are intended to have objects built from their 'blueprint' created in other classes that call them. Let me show you."
"In order to create an instance of a Banner object from our Banner class," I said, "we must first create a startup class. This startup class will look like the others that we've coded in the course so far. What you'll find strange, I'm sure, is the code necessary to create or instantiate the Banner object. Take a look…"
I then displayed this code on the classroom projector.
public class Example7_1 {
public static void main( String args[] ) {
Banner x = new Banner();
x.favoriteProgram = "Java";
x.display();
}
}
I could see much confusion on the faces of many of my students.
"Let's take a look at this code line by line," I said. "As you can see, this startup class begins like the others we've seen, with a class definition…"
public class Example7_1 {
"…The class definition is then followed by the main() method, which is require of every class that will be executed form a command prompt…"
public static void main( String args[] ) {
"What's going on with that next line of code?" Kathy asked. "I don't recall you discussing a Banner data type a few weeks back."
"This line of code looks just like a variable declaration, doesn't it," I said…
Banner x = new Banner();
"…in fact, it is. However, instead of seeing the familiar Java data types of int or String, what we see instead is a variable declaration that begins with the class name 'Banner'."
"Can you do that?" Ward asked.
"Yes we can," I said. "When you declare a variable of type int, Java allocates space in the computer's memory for an Integer data type. When you declare a variable of type Banner, Java allocates space in the computer's memory for the Banner object's Instance variables and for its method definitions."
"That's right," Dave said excitedly, "you did say that each object gets a 'copy' of the class's Instance variables and methods. So that's how it's done."
"That's right Dave," I said. "This syntax looks very confusing at first, but that's what's going on--we're telling Java to allocate enough 'room' in the PC's memory for a Banner object."
"What's x?" Lou asked.
"x is just the name of the variable," I said. "Hereafter, the instance of the Banner object we're about to create will be referred to by this name. But let's not forget the rest of the line--we also need to follow the variable name x with an equal sign, followed by the keyword 'new' followed by the name of the Banner class once again, followed by an empty pair of parentheses."
"What's the significance of the empty set of parentheses?" Linda asked.
"We'll see a little later on," I said, "that the new keyword tells Java to execute something known as the Constructor method of the Banner class. In this case, the empty set of parentheses tells Java to execute the Constructor method that requires no arguments. As it turns out, we didn't code a Constructor method in the Banner class---so Java automatically executes something known as the default Constructor method--all that means is that the Banner object is created."
"Will we learn how to create Constructor methods in this course?" Steve asked.
"Yes we will Steve," I said. "We'll spend quite a bit of time in today's class learning how to create Constructor methods."
I gave everyone a further chance to study the line of code that declares, and then creates an instance of a Banner object. It had been my experience that this single line of code may be the most confusing single concept for beginner Java programmers.
"You're right, this syntax is pretty confusing," Kate said. "I'm just so used to seeing a data type specified for a variable declaration. Seeing a Class name that we've defined ourselves specified as the type declaration is strange."
"I agree Kate," I said, "it is strange at first, but believe me, once you get used to it, declaring variables to refer to instances of your own classes will become second nature to you. As I think I've mentioned before, that's the name of the game in Java, and Java programmers are forever defining classes with attributes and behavior, and then instantiating objects from these classes in their programs."
"Can you go over how to change an object's attribute," Mary asked. "It seemed like you used an assignment statement, but I was a little confused by the syntax."
"Good question Mary," I said. "Once you've declared an instance of your class's object, you can easily set--by that I mean change---one of its attributes just by changing the value of the Instance variable that implements that attribute. Remember, behind the scenes, the attributes or characteristics of an object are really just Instance Variables defined in the object's class. Changing the attributes of an object is easy, but we can't just assign a value to the Instance variable, we need to assign a value to the Instance variable associated with this particular object. Because of that, we need to use a special notation called Object Dot Notation."
"Object Dot Notation?" Rhonda asked. "This is getting more complicated."
"It's not bad at all, Rhonda," I replied. "Object Dot Notation is just a way of telling Java the name of the object whose Instance variable we wish to update. With Object Dot Notation, we first specify the name of the variable that we used to declare an instance of our object, followed by a 'dot' or a period, followed by the name of the Instance variable that implements the attribute. After that, we're basically working with a ordinary Java assignment statement, in that we use the equal sign assignment operator, followed by the value we wish to assign to the Instance Variable…."
x.favoriteProgram = "Java";
"So what we've done here is change the value of the Instance Variable 'favoriteProgram' inside the Banner class?" Steve asked.
"That's close Steve," I said, "but more specifically, we've changed the value of the Instance Variable 'favoriteProgram' within a particular instance of the Banner object referenced by the variable 'x'. Remember, each object has its own 'copy' of every Instance variable and method in the memory. It's a subtle distinction, I know, but the distinction will become important later on today when we learn that we can create another type of variable within a class called a Class variable. A Class variable is a variable that is shared by every instance of an object instantiated from that class."
"I assume we can retrieve the value of an object's attribute using the same Object Dot Notation?" Ward asked.
"That's right Ward," I said. "we could display the value of the favoriteProgram attribute using this syntax…"
System.out.println(x.favoriteProgram);
"I see," Linda said, "really, except for the name of the object variable and the 'dot', this syntax is just like working with a variable."
"That's a good way of thinking about it," I said.
Everyone seemed to understand how to change, and view, the value of an Object's attribute.
"Calling the method for an Object that we've declared," I said, "should be familiar to you--it's the same way that we execute methods of the standard Java objects, such as System and JOptionPane. Once again, we use Object Dot Notation, specifying the name of our object variable, followed by a 'dot', followed by the name of the method we wish to execute…"
x.display();
"What's the purpose of the empty set of parentheses following the method name?" Mary asked.
"Any arguments required by the method appear within the parentheses," I said. "We defined the display() method of the Banner class to require no parameters---the empty set of parentheses are required when no arguments are required."
"I'm anxious to see Banner class in action," Rhonda said. "What do we need to do."
"First, we need to compile the Banner class," I said. "If we compile Example7_1 first, the Java compiler will find a reference to the Banner class in the program, will look for a compiled Banner Bytecode file, and if it doesn’t find it, will generate a compiler error for Example7_1."
"Where exactly does Java look for the compiled Banner Bytecode file?" Dave asked. "In the same folder as the Example7_1 class?"
"That's a good question Dave," I said. "The Java compiler will look for any Instantiable classes referenced in Example7_1 in the same folder in which Example7_1 is located. If the compiler doesn't find the other class there, then it looks to see if there's a Package Statement coded in the class. I showed you how to include a Package statement in your code a few weeks ago, I believe. For those of you who may have forgotten, the Package statement is a way of managing classes that are related to one another. When you include the Package statement in your class, you make that class a 'member' of that package. Most importantly, you tell Java to look in that package for any class references that it can't locate. We won't be specifically discussing Package creation on this class—just remember that in an application with a large number of classes, the Package statement can be used to manage those classes very effectively."
I then compiled the Banner class, followed by the Example7_1 class with no problem.
"Remember," I said, "we can't execute the Banner class from the command prompt--it has no main() method. We need to execute Example7-1 from the command prompt."
I did just that, an the following screen shot was displayed on the classroom projector.
Illustration 1
"Does everyone realize what's happened here?" I asked. "The code in Example7_1 created an instance of a Banner object from the Banner class, set the value of its favoriteProgram attribute, and executed its display() method."
"One class executing code in another," Kate said. "Pretty cool."
"I don't want to be a 'downer' about all of this," Rhonda said, "but couldn't we have just executed all of this code from a single startup class. What has this really bought us--quite honestly, I think it's complicated things."
"That's usually the first reaction that beginners have," I said. "You're right in that we could have placed all of the code we executed in a single class, and as you know, we could place it all within the main() method of a single class. But many years of experience has shown that modular programming---and in Java that means creating objects---leads to better programs. I think as the day progresses you'll begin to understand that placing code in classes whose objects are then instantiated within other classes actually 'uncomplicates' programs."
"Is it possible to create more than one instance of the same object in the startup class?" Bob asked. "For instance, suppose I was creating an instance of that Employee object you were describing earlier, and I wanted to 'instantiate' an object for every employee in a particular department."
"Yes it is possible," I said. "You just need to declare more than one object variable, like this…"
I then displayed the following code on the classroom projector….
public class Example7_2 {
public static void main( String args[] ) {
Banner x = new Banner();
Banner y = new Banner();
x.favoriteProgram = "Java";
x.display();
y.favoriteProgram = "C#";
y.display();
}
}
…compiled the program, and then executed it. The following screenshot was displayed on the classroom projector.
Illustration 2
"What we've done here," I said, "is to declare two instances of the Banner object…"
Banner x = new Banner();
Banner y = new Banner();
"I wouldn't have thought that was possible to have two object instances of the same class in a program," Blaine said.
"It's no problem," I said. "because as I mentioned earlier, each instance of an object is maintained separately in the computer's memory. Keeping the object and its attributes in separate locations of memory keeps one object from being confused with another. When we modify the attribute value of an object, Java knows exactly which object to act upon by the object variable name we use…"
x.favoriteProgram = "Java";
x.display();
y.favoriteProgram = "C#";
y.display();
"That's pretty amazing," Rhonda said. "Is there a limit to the number of objects you can instantiate?"
"The number of objects you can instantiate," I said, "is limited only by the available memory in your computer---since that's where the objects are maintained. In some large commercial applications, it's not unusual to have thousands of objects in memory at one time."
"I think working with Instantiable Classes like this to create objects is great," Ward said, "and I really can't wait to start working with them back at my office. Is there anything else we need to know about creating Instantiable classes?"
"There are some more features of Instantiable classes that I want to discuss with you that can give your programs tremendous power," I said. "For instance, we can write code that is automatically executed each time an instance of our object is created."
"Kind of like a start-up Macro in Microsoft Word," Valerie added.
"Constructor methods are very similar," I said. "Code that you want to be executed when an instance of an object is created from a class you place inside a special method called a Constructor Method. Constructor methods are named with the same name as the Class."
"What kind of code goes into a Constructor method?" Joe asked.
"Any kind of code that in some way initializes our object," I said.
"Initializes?" Rhonda asked.
"That's right Rhonda," I said, "For instance, if the class is used to gain access to records in a database, the Constructor method is an ideal location to place code that finds and opens the database. Other types of initialization code is to set attributes of the object--Instance Variables---to default values, if that's appropriate. For instance, if your class have a currentDate Instance variable, you could place code in its Constructor method to interrogate the System date on the user's PC, and set the value of the currentDate Instance variable accordingly."
"I see," Kate said. "that makes sense."
"Speaking of Instance variables," I said, "take a look at this code.."
I then displayed this code on the classroom projector
public class Example7_3 {
public static void main( String args[] ) {
Banner x = new Banner();
x.display();
}
}
…compiled the program, and then executed it. The following screenshot was displayed on the classroom projector.
Illustration 3
"What happened?" Blaine asked. "What's up with that message. What's null?"
"Null is a value that indicates that a variable has no value," I said. "What happened here is that we created an instance of a Banner object, but prior to assigning a value to the Instance variable favoriteProgram, we immediately executed the Banner object's display() method. We displayed in the Java Console the value of the favoriteProgram Instance variable---null."
"I hadn't noticed that we hadn't initialized the value of favoriteProgram," Dave said. "I thought that in Java you have to initialize your variables."
"That's the case only with local variables," I said, "Java doesn't require us to initialize Instance Variables. As a result, 'accidents' like this can easily happen. The bottom line is that it's a good idea to initialize all of our Instance Variables, either at the time we declare them, or as part of the Class's Constructor Method."
"Can you show us how to code a Constructor Method," Ward asked. "Is it complicated?"
"Creating a Constructor Method is very easy Ward," I said. "The Class Constructor Method is just an ordinary method with the same name as the class. For instance, the Constructor Method for the Banner Class would look like this…"
public Banner() {
System.out.println ("Banner's constructor");
}
NOTE
A Constructor is a method of the class, having the same name as the class, which is automatically executed when an object of the class is created.
"That is easy," Linda said, "I notice you didn't specify a return value for the method. Isn't that always required."
"That's a good point Linda," I answered. "Return values for methods are required--except in the case of a Constructor methods. In fact, Constructor Method MAY NOT return a value of any kind, not even the void return type."
"I'm going to have to remember that," Rhonda said, "that's the type of thing I'm likely to forget, but I guess the compiler will warn me."
"Unfortunately Rhonda," I said, "if by code a Constructor Method and by accident specify a return value, Java will still compile your class---but the Constructor method won’t automatically execute when an object of the class is created."
NOTE
A Constructor method may not specify a return value of any type—not even void
"I bet that can have you scratching your head for hours," Kate said. "Can we see the Constructor method in action?"
"Sure thing Kate," I said, "Let's modify the Banner Class to include a Constructor method--all we'll do is display a message in the Java Console that tells us the Constructor method has been executed."
I then modified the Banner class to look like this, and displayed its code on the classroom projector
public class Banner {
String favoriteProgram;
public Banner() {
System.out.println ("Banner's constructor");
}
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
"Does everyone see the Constructor method?" I asked. "It's the method called Banner()…"
public Banner() {
System.out.println ("Banner's constructor");
}
"…Notice that the name of the Constructor method is identical to the class name—and also notice that no return value is specified for the method."
"So when an object of this class is created," Steve asked, "the code in the Constructor method will automatically be executed?"
""That's right Steve," I said.
I then compiled the modified version of the Banner class.
"Here's some simple code that will illustrate the behavior of the Constructor method," I said, "All we're doing here is creating an instance of the Banner object, nothing else…"
public class Example7_4 {
public static void main( String args[] ) {
Banner x = new Banner();
}
}
I then compiled and executed the program. The following screenshot was displayed on the classroom projector.
Illustration 4
Table 1
"As you can see," I said, "when we executed this line of code in Example7_4…"
Banner x = new Banner();
"…the Banner object was created, and its Constructor method was automatically executed---that resulted in the message we see in the Java Console."
"What did you say earlier about using a Constructor to initialize Instance Variables?" Rhonda asked.
"Constructor's are also an ideal place to initialize any Instance Variables in your class with default or start up values," I said. "Let me show you."
I then displayed this modified code on the classroom projector.
public class Banner {
String favoriteProgram;
public Banner() {
System.out.println ("Banner's constructor");
favoriteProgram = "Java";
}
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
I then compiled the modified version of the Banner class.
"Do you remember when we executed Example7_3 a few minutes ago?" I asked.
"I do," Kate said, "because we didn't set the favoriteProgram attribute prior to executing the Banner object's display() method, we displayed the message 'I love null' in the Java Console window."
"Right on the mark Kate," I said. "Having changed the Banner class to initialize the value of favoriteProgram in its Constructor method, let's re-execute Example7_3, and see what happens…"
I then re-executed Example7_3, and the following screen shot was displayed on the classroom projector.
Illustration 5
"That's better isn't it," I said. "Now if the user forgets to tell us, via an assignment statement, what their favorite program is, we'll just display the default value of the favoriteProgram Instance variable."
"I'm a little confused," Rhonda said, "We changed the Banner class to include a Constructor method and recompiled it---didn't we need to recompile Example7_3 also?"
"No we didn't," I said, "when we declare and create an instance of the Banner object from within Example7_3, Java looks for the Banner Bytecode file and builds the Banner object based on the current definition of the class. Even though the Banner class was changed and recompiled, there's no need to recompile Example7_3."
"Is that true in all cases?" Dave asked pointedly. "For instance, suppose we changed the name of the display() method in the Banner class?"
"You're right Dave," I said. "In the word of Object-oriented programming," I said, "there is a presumed 'contract' between the designer of the object and the many users of the object, and there's also a hard and fast rule---DON'T BREAK THE CONTRACT. What that means is that a class should not be modified in such a way as to cause programs already using objects from that class to bomb"
"What could cause programs using the class to bomb?" Bob asked.
"A number of things," I said. "One reason would be the case that Dave just cited," I said. "A program that is written to execute a method of a class will bomb if the method name is changed, or removed altogether. Also, if the method's signature--the number and type of arguments---is changed, the program will bomb. "
"Obviously, adding a Constructor method to the class had no detrimental impact on Example7_3," Ward said.
"That's right Ward, " I said, "and that's a big benefit to modularizing code into objects like this. A minor change like this to the code in another class has no impact on the program using it."
"I understand," Peter said, "that if we change the name of a method, or change the signature of a method in a class, the program using its object will bomb. And I see that adding a new method to the class is not a problem. Suppose we change some of the code in an existing method? Is that a problem."
"That's the beauty of Object-oriented programming," I said. "By 'hiding' the details of exactly how a method does its work, and simply having the client program execute it, in theory a change to the method has no impact on the client program. For instance, when we add objects to the Grades Calculation project later on today, the code for the calculation of an English Student will reside in the calculate() method of an EnglishStudent object. If Frank Olley should request a change in the way the final grade for an English student is calculated, all we need to do is change the code in the method--any client program using the method won't have a problem."
"How often are the signatures of methods changed in the commercial world?" Valerie asked.
"They're usually not," I said. "If something requires a change to the method signature, it's better to create an…"
"Overloaded method," Kate yelled out. "Now I understand."
"You took the words right out of my mouth Kate," I said. "That's one good reason to create an overloaded method. By maintaining a method with the 'old' signature, and creating a method with the 'new' signature, you ensure that older programs will still run, while new programs can take advantage of the functionality in the new method."
"I know in the previous version of the Banner class, we didn't code a Constructor Method," Chuck said, "I assume that means the Constructor method is not required. Is that correct?"
"That's right Chuck," I answered. "Constructor methods are not required in a class—but as you'll learn as you progress in your Java career, coding a Constructor method is frequently a good idea. In fact, it's even possible to code more than one Constructor method for a class."
"You mean an Overloaded Constructor?" Dave asked.
"Exactly right Dave," I said, "When your class has two or more Constructor methods with the same name but with a different method signature you have overloaded Constructors."
"I didn’t realize you could pass arguments to a Constructor method," Kate said.
"Yes you can Kate," I said, "I'll show you an example of a Constructor method requiring arguments in a minute."
"Why would you want to create more than one Constructor method?" Rhonda asked.
"Since Constructor methods are automatically executed when an object of your class is created," I said, "coding overloaded Constructor methods gives the user of your program more flexibility in the way they create objects from your class. For example, you might code a Constructor method with no arguments. This Constructor, when executed, would create a 'no frills' object from your class, initializing Instance Variables to default values. But you might also want to code a Constructor method that does much more, such as permitting the creator of an object of your class to specify values for one or more Instance Variables at the time the object is created."
I could see some confusion in the classroom, and so I suggested that we modify the Banner Class to provide two Constructor methods.
"The first Constructor method," I said, "will have no arguments required, and will initialize the value of the favoriteProgram Instance Variable to 'Java'. The second Constructor method will require a single argument, and it will initialize the value of the favoriteProgram Instance Variable to whatever value is passed to the method."
I displayed the modified code for the Banner class on the classroom projector.
public class Banner {
String favoriteProgram;
public Banner() {
System.out.println ("Banner's constructor");
favoriteProgram = "Java";
}
public Banner(String param1 ) {
System.out.println ("Banner's overloaded constructor");
favoriteProgram = param1;
}
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
I then compiled the modified version of the Banner class.
"Do you see that we now have two Constructor methods?" I asked. "Both are named Banner---the first requires no arguments, but the second requires a single argument called param1…"
public Banner(String param1 )
{
System.out.println ("Banner's overloaded constructor");
favoriteProgram = param1;
}
"I was pretty comfortable in creating overloaded methods last week," Steve said, "and I see what you're doing here in the class to create the Overloaded Constructor Methods, but how do you 'call' an overloaded Constructor using the new keyword?"
"Let me show you," I said, as I displayed this program on the classroom projector.
public class Example7_5 {
public static void main( String args[] ) {
Banner x = new Banner(); // Call Constructor
x.display();
Banner y = new Banner("Visual Basic");
// Call Overloaded
y.display();
// Constructor
}
}
I then compiled and executed the program. The following screenshot was displayed on the classroom projector.
Illustration 6
"This syntax," I said, "creates an instance of the Banner object, and because there's nothing within the parentheses, Java automatically executes the Constructor method requiring no arguments…"
Banner x = new Banner();
"…when that Constructor Method is executed, the value of the favoriteProgram Instance Variable is set to "java', which is why when we executed this code…"
x.display();
"…'I love Java' was displayed in the Java Console window. This syntax creates an instance of the Banner object, and because there's a single String argument contained within the parentheses, Java automatically executes the Constructor method requiring a single String argument…"
Banner y = new Banner("Visual Basic");
"...when that Constructor method is executed, the value of the favoriteProgram Instance Variable is set to the value of the passed argument, which is 'Visual Basic', which is why when we executed this code…"
y.display();
"…'I love Visual Basic" was displayed in the Java Console window."
"This is really neat," Ward said, "I would imagine you could come up with quite a few different Constructor methods."
"That's right Ward," I said, "Programmers frequently have more than one. The important thing to remember is that Constructor methods are an ideal place for code to initialize the state of your object at the time of its creation."
"I mentioned earlier," I said, "that each object and its attributes or Instance Variables, are maintained in separate locations in the computer's memory. This protects the data in one object from being confused with the data of another object. There's another type of variable you can declare in a class called a Class variable which allows you to share its value with every instance of an object created from that class."
"I was just about to ask if such a thing was possible," Dave said. "I've worked with other languages where that was possible, and it can be a pretty beneficial feature."
"When you say share," Kate asked, "you mean that each object can see the value of the variable, and update it as well?"
NOTE
Class variables 'share' their data with every instance of the object created from the class
"That's right Kate," I said, "as Dave said, this can be a very beneficial feature. Class variables are a great way for objects of the same class to share data."
"Is that important?" Mary asked. "Is that something that's commonly required?"
"It can be," I said. "For instance, have you ever worked with an accounting program? One part of an accounting program typically is used to generate invoices to your customers, and it's customary to assign a unique invoice number to each invoice. If you write the accounting program using Java, each invoice can be an object, and you could create a Class Variable called nextInvoiceNumber which would enable each object to access the next available invoice number when the invoice object is created."
"I see what you mean," Valerie said, "that makes sense. By storing the value of the next invoice number in a Class variable, each instance of the object can 'get at' the value, plus increment the value by one after they use it."
"Excellent Valerie," I said.
"Can we add a Class Variable to the Banner class to see how it works?" Steve asked.
"Sure Steve," I said. "Do you remember that in Example7_2, we created two Banner objects, both of which were 'alive' at the same time. Suppose we want each object to be able to know how many Banner objects are currently 'alive'? A class variable is an ideal way to do that."
"How exactly would we do that?" Peter asked.
"We can declare an Integer Class Variable in the Banner class," I said, "and then, within its Constructor Method, increment the value of that Class Variable by 1. Since the Constructor method is automatically executed each time an object of the class is created, the value of the Class Variable should always reflect the number of Banner objects that are currently in existence."
I then modified the Banner class to look like this, and displayed it on the classroom projector.
public class Banner {
String favoriteProgram;
static int numberOfBannerObjects;
public Banner() {
System.out.println ("Banner's constructor");
numberOfBannerObjects++;
favoriteProgram = "Java";
}
public Banner(String param1 ) {
System.out.println ("Banner's constructor");
numberOfBannerObjects++;
favoriteProgram = param1;
}
public void howMany() {
System.out.println ("The number of Banner objects is " + numberOfBannerObjects);
}
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
I then compiled the new Banner class.
"Let's take a look at the new code in the Banner class," I said. "We've added a Class Variable called numberOfBannerObjects, added a line of code in each of the two Constructor methods, and created a new method called howMany(). Let's take a look at the declaration of the Class variable first. A Class Variable is like an Instance Variable in that it is declared 'outside' any methods in the class. What differentiates a Class Variable from an Instance Variable is that it is declared with the Static keyword…"
static int numberOfBannerObjects;
"Static means that numberOfBannerObjects is a Class variable and not an Instance variable?" Blaine asked.
"That's right Blaine," I said. I waited a moment before continuing.
"…We also needed to modify both Constructor methods to increment the value of the numberOfBannerObjects Class Variable by using the Increment (++) operator. Here's the code for the first Constructor method…"
public Banner()
{
System.out.println ("Banner's constructor");
numberOfBannerObjects++;
favoriteProgram = "Java";
}
"…and here’s the code for the second…"
public Banner(String param1 )
{
System.out.println ("Banner's constructor");
numberOfBannerObjects++;
favoriteProgram = param1;
}
"…Finally, here's the code for the new method called howMany(). This method will be used by client programs to display the number of Banner objects that are currently 'alive'…"
public void howMany()
{
System.out.println ("The number of Banner objects is " + numberOfBannerObjects);
}
"Now let's write the code to see the effect of the Class Variable in action." I said. "What we'll do is create two Banner objects, and then execute the howMany() method of each one…"
I then displayed this code on the classroom projector.
public class Example7_6 {
public static void main( String args[] ) {
Banner x = new Banner();
x.favoriteProgram = "Java";
x.display();
x.howMany();
Banner y = new Banner("C#");
y.display();
y.howMany();
}
}
and compiled and executed the program. The following screenshot was displayed on the classroom projector.
Illustration 7
"Do you see what's happened here?" I asked. "After we create the first instance of the Banner object using this syntax…"
Banner x = new Banner();
"…the value of the Class Variable numberOfBannerObjects is incremented by 1 (giving us 1) when the 'no arguments' Constructor Method is executed. Executing the howMany() method displays the value of that Class Variable (1) on the Java Console.,,,"
x.howMany();
"…this syntax is then used to create a second instance of the Banner object…"
Banner y = new Banner("C#");
"…this results in the value of the Class Variable numberOfBannerObjects being incremented by 1 (giving us 2) when the single argument version of the Constructor method is executed. Executing the howMany() method displays the value of the Class Variable (2) on the Java Console."
y.display();
"From this example, " Dave said, "I can see that both of our Banner objects can 'see' the value of the Class Variable numberOfBannerObjects, but can both of them modify its value?"
"Good question Dave," I said, "and the answer is 'yes'---each object can modify the value of the Class Variable. Take a look at this."
I then modified the code from Example7_6 to look like this…
public class Example7_7 {
public static void main( String args[] )
{
Banner x = new Banner();
x.howMany();
Banner y = new Banner();
y.howMany();
y.numberOfBannerObjects = 0;
x.howMany();
y.howMany();
}
}
and compiled and executed the program. The following screenshot was displayed on the classroom projector.
Illustration 8
"I know this code is a bit confusing," I said, "but it does illustrate the ability of an object to modify the value of a Class Variable. As we did in Example7-6, here we've also created two Banner objects. The first Banner object is created using this syntax…"
Banner x = new Banner();
"…and as a result, the 'no arguments' version of the Constructor method is executed, incrementing the value of the Class Variable numberOfBannerObjects from 0 to 1. Executing the howMany() method of the first Object results in the message 'The number of Banner objects is 1' being displayed on the Java console…"
x.howMany();
"…the second Banner object is then created using this syntax…"
Banner y = new Banner();
"…and once again, the 'no arguments' version of the Constructor method is executed, incrementing the value of the Class Variable numberOfBannerObjects from 1 to 2. Executing the howMany() method of the second Object results in the message 'The number of Banner objects is 2' being displayed on the Java console…"
y.howMany();
"…with this line of code, we gain direct access to the Class Variable numberOfBannerObjects, and update it to 0 using an assignment statement with the first Object…"
y.numberOfBannerObjects = 0;
"…Has the value of the Class Variable really been updated? It has, and we can prove that by executing the howMany() method of the second Banner object, resulting in the message 'The number of Banner objects is 0' being displayed on the Java Console…"
x.howMany();
. By the way, notice how we used the first object to update the Class Variable, and the second object to display its value---no matter, each object is working with the same Class variable. Not surprisingly, we get the same results in the Java Console when we execute the howMany() method of the second Banner object…"
y.howMany();
"I'm convinced, there really is just the single Class Variable called numberOfBannerObjects shared among all the objects created from the class," Rhonda said. "I think I'm really beginning to understand this. But isn't there a potential problem here?"
"How so Rhonda?," I asked.
"Well," she continued, "the Class Variable numberOfBannerObjects was intended to keep track of the number of Banner objects in existence, and one of our Objects was able to subvert that. If other objects are dependent upon the value of numberOfBannerObjects, being able to change the value we did here seems more than a little dangerous to me."
"You raise some good points Rhonda," I said, "and actually, this topic is one that we'll cover next week when we discuss ways to protect the data--variables---in our classes from intentioned and un-intentioned updates."
"Is there any way to 'validate' the types of updates that an object can make to Instance and Class variables," Dave asked.
"The answer is 'yes'," I said, "and again, next week, we'll spend the entire class examining ways to protecting the data within our objects. For example, we'll learn there are techniques we can use to prevent an object from directly updating an Instance or Class variable, by forcing all updates to be performed through special validation methods--- but more on that next week."
"I've got to say that I feel pretty confident about working with objects," Ward said. "Now that you've shown us how to create classes of our own, and create objects from them, is there anything special we need to know to destroy them. What happens to the objects we create in our program---do they just go away when the program that creates them ends?"
"There's no need in Java to explicitly destroy an object when you are done working with it," I said. There are some Object-oriented programming languages, in which the objects you create must be explicitly destroyed. Failing to do so can result in the object, its data and the code in its methods, remaining in memory, thereby consuming valuable memory resources, and creating a phenomenon called 'memory leaks'. But Java is not like that. Java performs automatic 'garbage collection.""
"What was that?" Rhonda said with a startle. "Did you say garbage collection?"
"That's right Rhonda," I said, "behind the scenes in the Java runtime environment is a program called the Java garbage collector. It keeps track of objects, and when it detects that an object is no longer being used by a program---because the program has ended---the garbage collection takes care of destroying the object for us, and in the process frees the computer's memory of the resources that were allocated for the object."
"I understand there's nothing we need to 'do' when we're done with an object" Linda said. "but suppose we would like to have code execute when the client program using our object is done with it--is there a way to do that."
"Java does permit us to code something called a Finalize method," I said, "The Finalize method is guaranteed to be executed just before the Java garbage collector does its job of destroying an object."
"The Finalize method sounds similar to the Constructor method," Kate said, "except that instead of executing when the object is born, it's executed just before it dies. How do we create one?"
"There are some pretty strict rules for creating the Finalize method," I said. "First, it must be named finalize, it must be declared with the Protected keyword, it returns a void data type, and it may accept no arguments. It's header should look like this…
protected void finalize()
"What kind of code would we place in the Finalize method?" Bob asked.
"Any kind of code that needs to be executed when the object dies," I said. "For instance, you might want to store the object's data in a database or file of some kind when the client program is done with it. Placing code in the object's Finalize method is one way to ensure that the data is saved prior to the object dying, when the values of its Instance variables would be lost. Let's modify the Banner class we've been using this morning to see the Finalize method in action."
I then displayed the modified code for the Banner class on the classroom projector.
public class Banner {
String favoriteProgram;
static int numberOfBannerObjects;
public Banner() {
System.out.println ("Banner's constructor");
numberOfBannerObjects++;
favoriteProgram = "Java";
}
public Banner(String param1 ) {
System.out.println ("Banner's overloaded constructor");
numberOfBannerObjects++;
favoriteProgram = param1;
}
protected void finalize() {
System.out.println ("Banner's finalize");
}
public void howMany() {
System.out.println ("The number of Banner objects is " + numberOfBannerObjects);
}
public void display() {
System.out.println ("I love " + favoriteProgram);
}
}
"Here's the code for the Finalize method," I said, "Nothing fancy here--we're just writing a message to the Java Console to let us know that the object is about to be destroyed by the Java Garbage Collector…"
protected void finalize()
{
System.out.println ("Banner's finalize");
}
"Now let's write some code to see the Finalize method in action," I said. "I need to warn you that I'm going to 'force' the execution of the garbage collector by executing the gc() method of the System object. As I mentioned, the Java garbage collector runs on its own in the Java runtime environment---the problem with that is we might have to wait several minutes before it detects that our Banner object is no longer being used and destroys it. For that reason, we'll assign a null value to the Banner object and then force the garbage collector to destroy our object--this will give us a chance to see the Finalize method execute."
I then displayed this code on the classroom projector…
public class Example7_7 {
public static void main( String args[] )
{
Banner x = new Banner();
x.favoriteProgram = "Java";
Banner y = new Banner("C#");
x=null;
//Tell garbage collector we're done with object
y=null;
//Tell garbage collector we're done with object
System.gc();
//Force execution of the Garbage Collector
}
}
and compiled both this program and the modified Banner program. After executing Example7_7, the following screenshot was displayed on the classroom projector.
Illustration 9
"Does everyone see what happened here?" I asked. "We created two Banner objects, triggering their Constructor methods, then when the Java garbage collector was about to destroy them, the finalize method of the object was triggered."
"We wouldn't ordinarily have to do anything to make the garbage collector run, is that right?" Kathy asked.
"That's right Katy," I said. "Only for purposes of demonstration did we have to set our objects to null…"
x=null;
//Tell garbage collector we're done with object
y=null;
//Tell garbage collector we're done with object
"and then execute the gc() method of the System object…"
System.gc(); //Force execution of the Garbage Collector
"This is all great stuff," Rhonda said, "but I'd be lying if I didn't say that I would feel a lot more confident about creating my own classes and objects if I had a chance to work with them a little bit. Will we have time to do that today?"
"Absolutely," I said. "I have a series of exercises for you to complete that will give you plenty of practice in creating classes and objects. We'll start by taking the Smiley National Bank program we created last week, and modifying it to use objects. Then, towards the end of today's class, you'll modify he Grades Calculation project to use objects also."
We had been working a long time without a break, and so I asked everyone to take a fifteen minute break. When my students returned, I distributed this exercise for them to complete.
In this exercise, you'll take the code you wrote last week in Practice6_2, and include it in a BankTransaction class. This class will then be used by a client program you'll write in Exercise 7-2 to instantiate BankTransaction objects which will handle the details of making Deposits, Withdrawals, and displaying Bank Balances.
import javax.swing.JOptionPane;
public class BankTransaction {
double adjustment;
double newBalance;
static double balance;
// Class variable
public BankTransaction() {
System.out.println ("BankTransaction's constructor");
}
public void makeDeposit() {
adjustment = Double.parseDouble(JOptionPane.showInputDialog( "Enter the Deposit Amount" ));
newBalance = balance + adjustment;
JOptionPane.showMessageDialog(null, "*** SMILEY NATIONAL BANK ***\n\n" +
"Old Balance is: " + balance + "\n" +
"Adjustment is: +" + adjustment + "\n" +
"New Balance is: " + newBalance + "\n");
balance = newBalance;
}
// end of makeDeposit method
public void makeWithdrawal() {
adjustment = Double.parseDouble(JOptionPane.showInputDialog( "Enter the Withdrawal Amount" ));
newBalance = balance - adjustment;
JOptionPane.showMessageDialog(null, "*** SMILEY NATIONAL BANK ***\n\n" +
"Old Balance is: " + balance + "\n" +
"Adjustment is: -" + adjustment + "\n" +
"New Balance is: " + newBalance + "\n");
balance = newBalance;
}
// end of makeWithDrawal method
public void getBalance() {
JOptionPane.showMessageDialog(null, "*** SMILEY NATIONAL BANK ***\n\n" +
"Your Current Balance is: " + balance );
}
// end of getBalance method
}
// end of class
Creating the BankTransaction Instantiable class took us about fifteen minutes to complete. Much to my surprise, most of the students seemed comfortable completing the exercise---I think they were beginning to enjoy working with objects..
"Somehow I thought this would be more confusing," Rhonda said, "but I think I've surprised myself by more or less understanding what's going on here. Not only that, but I'm beginning to get the sense that the changes we've made to the Smiley National Bank application are doing exactly what you said they would do--make the program easier to read, follow, and modify in the future. If I'm correct, what we've done in this Exercise is take a bunch of code out of Practice6_2, and include it in an Instantiable object called BankTransaction. Is that right?"
"That's right Rhonda," I said. "We've taken some—but not all---of the code we had in written in Practice6_2---and included it in a BankTransaction class, from which we will create objects from a client program. BankTransaction contains three variables. Two of the variables, adjustment and balance, are Instance Variables, which means that each object created from the class has a separate copy of them. One variable however, newBalance, was designated with the Static keyword, and that means it's a Class variable."
"A Class variable can be seen by every objects of that class," Ward said, "plus, it exists for as long as any object of that class is alive."
"That's excellent Ward," I said.
"Why is balance declared as a Class Variable?" Peter asked.
"Designating balance as a Class variable," I said, "will enable our client program to keep a 'running total' of the bank account balance as it is updated by various objects."
"How many methods are there in the BankTransaction class," Chuck asked.
"The BankTransaction class has three methods," I said, "makeDeposit(), makeWithdrawal() and getBalance()). The code in each of these methods hasn't changed from that found in the methods in Practice6_2---all we've done is move the methods from a Startup class to an Instantiable class."
"You're right," Valerie said, "I was a little amazed at that myself---it seems that the work we did last week in creating custom methods for this application enabled us to create the BankTransaction Class pretty easily."
I waited a moment to see if there were any questions. No one had any, and so I distributed this exercise to create the client program in which we would instantiate objects from the BankTransaction class we just created.
In this exercise, you'll create a client program to instantiate objects from the BankTransaction class you created in Exercise 7-1.
import javax.swing.JOptionPane;
class Practice7_1 {
public static void main (String[] args) {
String response;
String moreBankingBusiness;
moreBankingBusiness = JOptionPane.showInputDialog( "Do you want to do some banking?" );
moreBankingBusiness = moreBankingBusiness.toUpperCase();
while (moreBankingBusiness.equals ("YES")) {
response = JOptionPane.showInputDialog( "What would you like to do? (1=Deposit, 2=Withdraw, 3=Get Balance)");
if (response == null) {
JOptionPane.showMessageDialog(null, "You clicked on the Cancel button");
System.exit (0);
}
else
if (response.equals("")) {
JOptionPane.showMessageDialog(null, "You must make an entry in the InputBox");
System.exit (0);
}
else
if (Integer.parseInt(response) < 1 | Integer.parseInt(response) > 3)
{
JOptionPane.showMessageDialog(null, response + " - is not a valid student type");
System.exit (0);
}
if (Integer.parseInt(response) == 1) {
BankTransaction transaction = new BankTransaction();
transaction.makeDeposit();
}
if (Integer.parseInt(response) == 2) {
BankTransaction transaction = new BankTransaction();
transaction.makeWithdrawal();
}
if (Integer.parseInt(response) == 3) {
BankTransaction transaction = new BankTransaction();
transaction.getBalance();
}
moreBankingBusiness = JOptionPane.showInputDialog( "Do you have more banking business?" );
moreBankingBusiness = moreBankingBusiness.toUpperCase();
}
// end of while
JOptionPane.showMessageDialog(null, "Thanks for banking with us!");
System.exit (0);
}
// end of main
}
// end of class
Discussion
"This program behaves in an identical manner to the code in Practice6_2," I said. "the difference is in the way the code is implemented, with this version using a client program to create instances of the BankTransaction object we created in Exercise 7-1. In this version of the program, it's the BankTransaction object that does the majority of the work. This client program creates objects, and based on the type of banking business the user wishes to transaction, executes one of the three methods of the BankTransaction class…"
if (Integer.parseInt(response) == 1) {
BankTransaction transaction = new BankTransaction();
transaction.makeDeposit();
}
if (Integer.parseInt(response) == 2) {
BankTransaction transaction = new BankTransaction();
transaction.makeWithdrawal();
}
if (Integer.parseInt(response) == 3) {
BankTransaction transaction = new BankTransaction();
transaction.getBalance();
}
"We've really taken the notion of modular programming to its extreme, by creating classes and objects, haven't we?" Dave commented.
"That's right, Dave" I said. "By 'encapsulating' the code for making deposits, withdrawals and displaying balances in the BankTransaction object, all the client program using our object needs to know is how to instantiate the object, what methods to execute. It's pretty easy, isn't it?"
"Will we be modifying the Grades Calculation Project to use objects today?" Joe asked.
"That's our next step Joe," I said. "Right now, the Grades Calculation project contains a single Startup class called Grades. Grades contains eight methods—main(), whatKindOfStudent(), calculateEnglishGrade(), calculateMathGrade(), calculateScienceGrade(), and three overloaded methods called displayGrade() to handle each of the three different types of student grade calculations. Any suggestions as to how we can 'turn' this code into an Instantiable class?"
"I guess we could create a single class called Student," Mary said, "having the same methods that we created last week. That's essentially what we just did with the Banking program."
"That's a possibility," I agreed.
"From what I've been reading about Object oriented programming," Dave said, "I think we need at least three classes---one for each of the three different types of students."
"Is that right?" Rhonda said, turning to Dave, but addressing her question to me.
"Dave's on the right track," I said. "This will make more sense to you when we discuss a concept called Inheritance in two weeks, but it makes the most sense to create a separate class for each type of student. Mary, I'd have no objection if you created a single class called Student---I mean you wouldn't really be wrong, but you'll see that creating three student classes is the way to go."
"Sounds great," Rhonda said, "I'm ready to start!"
"I'd also like to suggest that we create one other class called DisplayGrade," I said. "We currently have three overloaded methods called DisplayGrade, and I think that fact tells us that displaying grades is a distinct function in this program---creating an object to handle it will make things even easier on us."
"If the EnglishStudent, MathStudent, and ScienceStudent objects do the work of prompting the user for information, and calculating a grade" Dave said "and the DisplayGrade object takes care of displaying the student's grade, I think we have ourselves a very modular program."
"Yes it is," I agreed.
"Is there more than one way to design the classes in this project?" Blaine asked. "I hadn't thought of a DisplayGrade class at all."
"That's a good question Blaine," I said, "I want to emphasize that while there are some agreed upon 'rules' for the construction of objects, believe me, if we asked five programmers to review the requirements for this project, and asked them to design classes based on them, I bet we would come up with five different object models. As I frequently say, in the world of programming, there are many ways to paint a picture, and there's rarely a single, correct solution to a problem."
"Can we get going on this," Rhonda repeated impatiently. "This sounds like great fun to me, and I'm anxious to get started."
I then distributed this exercise for the class to complete.
In this exercise, you'll create the EnglishStudent class for the Grades Calculation project. This class will allow a client program to create an object which will prompt the user for information necessary to calculate the final grade for an English student.
import javax.swing.JOptionPane;
class EnglishStudent {
final double ENGLISH_MIDTERM_PERCENTAGE = .25;
final double ENGLISH_FINALEXAM_PERCENTAGE = .25;
final double ENGLISH_RESEARCH_PERCENTAGE = .30;
final double ENGLISH_PRESENTATION_PERCENTAGE = .20;
int midterm = 0;
int finalExamGrade = 0;
int research = 0;
int presentation = 0;
double finalNumericGrade = 0;
String finalLetterGrade = "";
public EnglishStudent() {
System.out.println ("EnglishStudent's constructor");
}
public void calculate() {
midterm = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Midterm Grade" ));
finalExamGrade = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Final Examination Grade" ));
research = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Research Grade" ));
presentation = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Presentation Grade" ));
finalNumericGrade =
(midterm * ENGLISH_MIDTERM_PERCENTAGE) +
(finalExamGrade * ENGLISH_FINALEXAM_PERCENTAGE) +
(research * ENGLISH_RESEARCH_PERCENTAGE) +
(presentation * ENGLISH_PRESENTATION_PERCENTAGE);
if (finalNumericGrade >= 93)
finalLetterGrade = "A";
else
if ((finalNumericGrade >= 85) & (finalNumericGrade < 93))
finalLetterGrade = "B";
else
if ((finalNumericGrade >= 78) & (finalNumericGrade < 85))
finalLetterGrade = "C";
else
if ((finalNumericGrade >= 70) & (finalNumericGrade < 78))
finalLetterGrade = "D";
else
if (finalNumericGrade < 70)
finalLetterGrade = "F";
}
}
Discussion
No one had any trouble creating the EnglishStudent class, although I did notice a student or two try to execute the class from the Command Prompt---something you can't do since the EnglishStudent class is an Instantiable class.
"I noticed that you changed the name of the method calculateEnglishGrade() to calculate()," Dave said, "Is there a reason for that?"
"There's an object oriented programming term called 'polymorphism'," I said, "which means it's OK---even preferable---to have identically named methods in different classes, provided the methods perform the same function. Since each one of our student classes has a method to perform a calculation, I thought it made sense to give each one of them the same name. Therefore, we'll have a calculate() method in each one of the three student classes."
"I noticed that we have a Constructor method in the class," Linda said. "Is that really necessary."
"You're right Linda," I said, "we coded a Constructor method, although as you can see it doesn't do very much…"
public
EnglishStudent() {
System.out.println ("EnglishStudent's constructor");
}
"…whenever I'm developing a new application, I like to code Constructor methods that write a message out to the Java Console. That way, when I run the program, I can see if, and when, my objects are being created. This can sometimes help you understand how your programming is behaving. At any rate, it can't hurt---provided we remember to remove the code from the Constructor methods prior to delivering the final version of the program to Frank Olley."
There were no other questions, and so we moved onto creating the MathStudent class.
In this exercise, you'll create the MathStudent class for the Grades Calculation project. This class will allow a client program to create an object which will prompt the user for information necessary to calculate the final grade for a Math student.
import javax.swing.JOptionPane;
class MathStudent {
final double MATH_MIDTERM_PERCENTAGE = .50;
final double MATH_FINALEXAM_PERCENTAGE = .50;
int midterm = 0;
int finalExamGrade = 0;
int research = 0;
double finalNumericGrade = 0;
String finalLetterGrade = "";
public MathStudent() {
System.out.println ("MathStudent's constructor");
}
public void calculate() {
midterm = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Midterm Grade" ));
finalExamGrade = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Final Examination Grade" ));
finalNumericGrade =
(midterm * MATH_MIDTERM_PERCENTAGE) +
(finalExamGrade * MATH_FINALEXAM_PERCENTAGE);
if (finalNumericGrade >= 90)
finalLetterGrade = "A";
else
if ((finalNumericGrade >= 83) & (finalNumericGrade < 90))
finalLetterGrade = "B";
else
if ((finalNumericGrade >= 76) & (finalNumericGrade < 83))
finalLetterGrade = "C";
else
if ((finalNumericGrade >= 65) & (finalNumericGrade < 76))
finalLetterGrade = "D";
else
if (finalNumericGrade < 65)
finalLetterGrade = "F";
}
}
// end of class
Again, there were no major problems in completing the exercise, and to my surprise, absolutely no question. We then moved onto the next exercise—the creation of the ScienceStudent class.
In this exercise, you'll create the ScienceStudent class for the Grades Calculation project. This class will allow a client program to create an object which will prompt the user for information necessary to calculate the final grade for a Science student.
import javax.swing.JOptionPane;
class ScienceStudent {
final double SCIENCE_MIDTERM_PERCENTAGE = .40;
final double SCIENCE_FINALEXAM_PERCENTAGE = .40;
final double SCIENCE_RESEARCH_PERCENTAGE = .20;
int midterm = 0;
int finalExamGrade = 0;
int research = 0;
double finalNumericGrade = 0;
String finalLetterGrade = "";
public ScienceStudent() {
System.out.println ("ScienceStudent's constructor");
}
public void calculate() {
midterm = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Midterm Grade" ));
finalExamGrade = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Final Examination Grade" ));
research = Integer.parseInt(JOptionPane.showInputDialog( "Enter the Research Grade" ));
finalNumericGrade =
(midterm * SCIENCE_MIDTERM_PERCENTAGE) +
(finalExamGrade * SCIENCE_FINALEXAM_PERCENTAGE) +
(research * SCIENCE_RESEARCH_PERCENTAGE);
if (finalNumericGrade >= 90)
finalLetterGrade = "A";
else
if ((finalNumericGrade >= 80) & (finalNumericGrade < 90))
finalLetterGrade = "B";
else
if ((finalNumericGrade >= 70) & (finalNumericGrade < 80))
finalLetterGrade = "C";
else
if ((finalNumericGrade >= 60) & (finalNumericGrade < 70))
finalLetterGrade = "D";
else
if (finalNumericGrade < 60)
finalLetterGrade = "F";
}
}
"These three classes have been very similar," I said. "with just minor differences in the way the final grade is calculated. This is something that will come into play when we discuss inheritance in two weeks."
There were no questions, and so I distributed this exercise for the class to complete.
In this exercise, you'll create the DisplayGrade class for the Grades Calculation project. This class will allow a client program to create an object which will display the final grade for either an English, Math or Science student. This class has three overloaded Constructor methods to code--so be careful.
import javax.swing.JOptionPane;
class DisplayGrade {
public DisplayGrade(int midterm, int finalExamGrade,
int research, int presentation, double finalNumericGrade, String finalLetterGrade)
{
JOptionPane.showMessageDialog(null, "*** ENGLISH STUDENT ***\n\n" +
"Midterm grade is: " + midterm + "\n" +
"Final Exam is: " + finalExamGrade + "\n" +
"Research grade is: " + research + "\n" +
"Presentation grade is: " + presentation + "\n\n" +
"Final Numeric Grade is: " + finalNumericGrade + "\n" +
"Final Letter Grade is: " + finalLetterGrade);
}
// end of displayGrade method with 6 parameters
public DisplayGrade(int midterm, int finalExamGrade,
double finalNumericGrade, String finalLetterGrade) {
JOptionPane.showMessageDialog(null,"*** MATH STUDENT ***\n\n" +
"Midterm grade is: " + midterm + "\n" +
"Final Exam is: " + finalExamGrade + "\n\n" +
"Final Numeric Grade is: " + finalNumericGrade + "\n" +
"Final Letter Grade is: " + finalLetterGrade);
}
// end of displayGrade method with 4 parameters
public DisplayGrade(int midterm, int finalExamGrade, int research,
double finalNumericGrade, String finalLetterGrade) {
JOptionPane.showMessageDialog(null,"*** SCIENCE STUDENT ***\n\n" +
"Midterm grade is: " + midterm + "\n" +
"Final Exam is: " + finalExamGrade + "\n" +
"Research grade is: " + research + "\n\n" +
"Final Numeric Grade is: " + finalNumericGrade + "\n" +
"Final Letter Grade is: " + finalLetterGrade);
}
// end of displayGrade method with 5 parameters
}
// end of class
No one seemed to have any problems completing the exercise, but I could sense some confusion.
"Does everyone understand what's going on here?" I asked. "We've created a class that has three overloaded Constructor methods."
"Constructor methods have the same name as the class, is that right?" Rhonda asked. "and they are automatically executed when an object from the class is created."
"That's excellent Rhonda," I said. "Constructor methods are guaranteed to execute when an object of the class is created. Furthermore, you can create more than one Constructor method with the same name. These are called Overloaded Constructor Methods, and Java decides which one of them to execute based on the number and type of arguments passed to the Constructor when the object is created. I'll give you a preview of the code change we're about to make in the Grades class---this is the code which will instantiate a DisplayGrade object and pass the Constructor method six arguments to display the final grade for an English Student…"
DisplayGrade x = new DisplayGrade (midterm,finalExamGrade,research,presentation,finalNumericGrade, finalLetterGrade);
No one had any other questions, and so we moved onto the final exercise of the day---modifying the Grades class to create objects from the Instantiable classes we had just created.
Exercise 7-7
Modify the Grades Calculation program to use Instantiable objects
In this exercise, you'll modify the Grades class from last week to create objects from the Instantiable classes you just created.
import javax.swing.JOptionPane;
class Grades {
public static void main(String args[]) {
String moreGradesToCalculate;
String response;
moreGradesToCalculate = JOptionPane.showInputDialog( "Do you want to calculate a grade?" );
moreGradesToCalculate = moreGradesToCalculate.toUpperCase();
while (moreGradesToCalculate.equals ("YES")) {
response = whatKindOfStudent();
switch(Integer.parseInt(response)) {
case 1:
EnglishStudent eStudent = new EnglishStudent();
eStudent.calculate();
DisplayGrade x = new DisplayGrade (eStudent.midterm,
eStudent.finalExamGrade,
eStudent.research,
eStudent.presentation,
eStudent.finalNumericGrade,
eStudent.finalLetterGrade);
break;
case 2:
MathStudent mStudent = new MathStudent();
mStudent.calculate();
DisplayGrade y = new DisplayGrade (mStudent.midterm,
mStudent.finalExamGrade,
mStudent.finalNumericGrade,
mStudent.finalLetterGrade);
break;
case 3:
ScienceStudent sStudent = new ScienceStudent();
sStudent.calculate();
DisplayGrade z = new DisplayGrade (sStudent.midterm,
sStudent.finalExamGrade,
sStudent.research,
sStudent.finalNumericGrade,
sStudent.finalLetterGrade);
break;
default:
JOptionPane.showMessageDialog(null, response + " - is not a valid student type");
System.exit (0);
}
moreGradesToCalculate = JOptionPane.showInputDialog( "Do you have another grade to calculate?" );
moreGradesToCalculate = moreGradesToCalculate.toUpperCase();
}
JOptionPane.showMessageDialog(null, "Thanks for using the Grades Calculation program!");
System.exit (0);
}
// end of main
public static String whatKindOfStudent() {
String response;
response = JOptionPane.showInputDialog( "Enter student type (1=English, 2=Math, 3=Science)" );
if (response == null) {
JOptionPane.showMessageDialog(null, "You clicked on the Cancel button");
System.exit (0);
}
else
if (response.equals("")) {
JOptionPane.showMessageDialog(null, "You must make an entry in the InputBox");
System.exit (0);
}
else
if (Integer.parseInt(response) < 1 | Integer.parseInt(response) > 3)
{
JOptionPane.showMessageDialog(null, response + " - is not a valid student type");
System.exit (0);
}
return response;
}
// end of whatKindOfStudent method
}
Changing the Grades Class to use Instantiable objects was pretty tedious---it took most of my students about 15 minutes to complete the exercise. Despite that, there were no major problems, and I think most everyone understood what was going on.
"In the final analysis," Ward said, "we took a bunch of the code from the Grades class, and placed it in the EnglishStudent, MathStudent, ScienceStudent, and DisplayGrade classes. Is that right?"
"That's right Ward," I said, "Notice that the code in the Grades class itself has been drastically reduced--moved into one of four other classes. Most importantly, the code is easier to read, understand and maintain."
"How so?" Rhonda asked.
"Let me ask you this question," I said. "If Frank Olley walked into our classroom right now, and told you that the calculation of the final grade for an English Student needs to be changed, can you tell me what class we would need to change?"
"That's easy," Dave said. "That code is in the EnglishStudent class--in fact, it's in the calculate() method of the EnglishStudent class."
"I couldn't have said it better myself Dave," I said.
"Can you review the code that instantiates the various student objects?" Barbara said.
"Sure thing Barbara," I said, "here it is…"
switch(Integer.parseInt(response)) {
case 1:
EnglishStudent eStudent = new EnglishStudent();
eStudent.calculate();
DisplayGrade x = new DisplayGrade (eStudent.midterm,
eStudent.finalExamGrade,
eStudent.research,
eStudent.presentation,
eStudent.finalNumericGrade,
eStudent.finalLetterGrade);
break;
case 2:
MathStudent mStudent = new MathStudent();
mStudent.calculate();
DisplayGrade y = new DisplayGrade (mStudent.midterm,
mStudent.finalExamGrade,
mStudent.finalNumericGrade,
mStudent.finalLetterGrade);
break;
case 3:
ScienceStudent sStudent = new ScienceStudent();
sStudent.calculate();
DisplayGrade z = new DisplayGrade (sStudent.midterm,
sStudent.finalExamGrade,
sStudent.research,
sStudent.finalNumericGrade,
sStudent.finalLetterGrade);
break;
"All of the code necessary to instantiate the EnglishStudent, MathStudent, or ScienceStudent objects is contained within this Switch structure. The test condition for the Switch structure is the user's response of 1, 2 or 3 in an Inputbox. If the user's response is 1, we declare an instance of the EnglishStudent object, using the object variable eStudent…."
EnglishStudent eStudent = new EnglishStudent();
"…we then execute the calculate() method of the EnglishStudent object using this code…"
eStudent.calculate();
"…followed by an instantation of the DisplayGrade object. Depending upon the number and type of arguments supplied, one of the three Constructor methods we created is executed…"
DisplayGrade x = new DisplayGrade (eStudent.midterm,
eStudent.finalExamGrade,
eStudent.research,
eStudent.presentation,
eStudent.finalNumericGrade,
eStudent.finalLetterGrade);
"I probably should have asked this earlier," Linda said, "but why didn't we place the code for the grade calculation in a Constructor method of the EnglishStudent class---like we did with the DisplayGrade class---instead of creating a separate method called calculate()."
"That's a good question Linda," I said. "We certainly could have done. Another case of there being more than one way to paint a picture. In theory, Constructor methods should be used to initialize the 'state' or data variables of an object. I 'stretched' the intended purpose of the Constructor methods for the DisplayGrade object just a bit---in part because I wanted to give you all a chance to work with one."
I waited to see if anyone had any questions, but there were none.
"This class has been a very productive one," I said, "in that we learned how to code classes, and create objects from them which gives us access to the object's data and behavior. Next week we'll learn that sometimes in our haste to give a client program access to an object's data, we permit too much access--which can have some pretty nasty effects on the data integrity of our objects. We'll learn how to correct that problem next week."
With that, I dismissed the class for the day.
In this chapter, we learned how we can create Instantiable classes—that is, classes from which objects can be created. These objects can have attributes, which are implemented via instance and class variables within the class, and behavior, which is implemented via class methods. Instantiable classes cannot be executed via a command prompt—their objects must be created from within another class—typically a startup class possessing a main() method. Instantiable objects are created using the New keyword. Instantiable objects are destroyed by the Java garbage collector when no program is using them any longer. There is no need to explicitly destroy a Java object as there is in other programming languages. The garbage collector will take care of this for you.
Instantiable classes have two special types of methods. The first, the Constructor method is a method with the same name as the class, and its code is guaranteed to execute when an object of the class is first created. Constructor methods may be overloaded—that is, you may have more than one Constructor method with the same name, provided each one has a different 'signature'---the number and type of arguments.
The second special method is called a Finalize method, and its code is guaranteed to execute when the Java garbage collector is about to destroy the object. Finalize methods must be named 'finalize', and should be declared with the Protected keyword, and return a void return value.