CS 302 Lab 8

Lab 8: Exploring the Flexibility of Classes in Java

CS302, UW-Madison

Today We'll be:

Overview

The concept of a class in Java is more flexible than what you've seen so far in lab, and we want to show you more options that Java programmers have in the ways they use classes. Up to this point, we've used classes in the following ways:

In this lab you'll be using a Java class in old and new ways. You'll be doing this by creating an instantiable class that represents a credit card.

Task 1: Researching Credit Cards

We've learned that our programs often need to represent and use objects that are more complex than simple numbers or characters. A credit card is a good example of such an object. Credit cards are issued by many different kinds of institutions including banks and stores. There are also different kinds of credit cards, the two most common being VISA and MasterCard. When you establish a credit account, you're issued a plastic card that contains pertinent information that enables you to purchase things using your line of credit. That card will likely be replaced many times over the years that you have the credit account. For example, a new card is issued when your name changes (e.g., marriage), or after an expiration date on a card has passed. Take a few minutes to consider:

After you've thought about what information is on a credit card, take a look at: front and back.

Assume that you're designing a credit card class for a company like VISA or MasterCard, and they'll use our class in a database application program for manufacturing the cards. We'll be telling you what information to put in the class as you incrementally implement it below.

Task 2: Combining a Driver or Tester with its Instantiable Class

The driver or test program that tests an instantiable class can be combined with its instantiable class. Some programmers prefer this approach rather than having two separate classes. Lets see how this works. Create a new project in Eclipse named Credit Card Lab, and then create a new class named CreditCard in your Credit Card Lab project.

Now let's add some code to the CreditCard class. Add instance variables into your CreditCard class for:

Use the identifiers name and issuer for the first two instance variables. Then code at least one constructor, and accessors (getters) and mutators (setters) for these instance variables. (Don't worry about the credit card number; we'll add that in a task below.) Make sure to comment your class as you code it.

Now add a main method to your CreditCard class and don't forget to also add the main method header comment. This method will be used as your driver program. In this main method construct a CreditCard object and then display the card's information using your accessor (getter) methods. Add additional code to this main method to test each of your CreditCard class's mutator (setter) and accessor (getter) methods.

Task 3: toString

We've learned to use accessors to get the information in an object for outputting as in this example:

System.out.println(card1.getName() + ", " + card1.getIssuer());

What happens when you only put a reference variable in a print or println statement? Let's give this a try. Make two new credit card objects using the reference variables names card1 and card2. Add code to your main method to display these credit card reference variables like this:

System.out.println(card1);
System.out.println(card2);

What do you think this output is showing you?

Using accessors as is initially shown above cumbersome, but using just the reference variable doesn't show us the contents of the object. Fortunately, Java provides a more convenient way to output objects if we define in our class a method named toString. This method must have the following heading: public String toString(), and the body of the method returns a String that represents the object. For example, we could implement the following:

public String toString() {
    return this.name + ", " + this.issuer;
}

If we do this, then we can output CreditCard objects is a much easier way:

System.out.println(card1);

Why does this work? Java is designed to use the toString method to output objects. If you don't provide a toString method in your instantiable class, then Java uses a default toString method that displays the object's class name and memory address as you've seen above.

Add a toString method and header comment to your CreditCard class, then test it in your main method by using it in a print statement (as shown above).

Task 4: Instance Constants

Sometimes an object's information doesn't change, that is, it remains constant for the life of the object. The number on a credit card is an example of information that doesn't change -- it is the credit account number and exists for the life of the account. Note that each credit card will have its own unchanging card number. Java programmers have given the name instance constant for this kind of information. The typical form for declaring an instance constant is:

public final <type> <NAME>;
An instance constant can only be assigned its value in constructors (or in the declaration). You cannot use a mutator (setter) method to do this. For example, if we were to code up a different class for a Book we would do:
public final long ISBN;
private String title;

public Book(String title, long isbn) {
    this.title = title;
    this.ISBN = isbn;
}

Also note that since instance constants cannot be changed, we can make them public so that we don't have to write accessor methods to access them.

Give this a try by adding a 16 digit credit card number as an instance constant in the CreditCard class. Carefully consider what data type to use for the 16 digit number. Modify your constructor(s) and your toString method to make use of this new information. Then add code to your main method to construct a credit card with a 16 digit number (note: you'll need to put an L after the 16 digit value as in this example 1234567890123456L). Also display the card and directly access and display its number in the main method using the form:
<object name>.<INSTANCE CONSTANT NAME>

Task 5: Class Constants and Class Variables

Instance constants and instance variables specify information that each object stores. Java also allows you to specify information that is shared by all objects of a class, rather than each object storing its own copy. These are called class constants and class variables. Java programmers commonly call these static constants and static variables since we use the reserved word static in their declarations. static tells the compiler that something is for the class rather than for each instance of the class.

Class Constants

First add a class constant to your CreditCard class. The typical form for specifying a class constant is:

public static final <type> <NAME> = <value>;

At the beginning we assumed that we were designing this class for a single credit card type such as VISA or MasterCard. All of the credit cards that are constructed will be fixed to one type of card. Add a class constant that stores the card type, that is, it stores either "VISA", "MasterCard", "Discover", etc. Then modify your toString method to display this new information, and verify your main method now also displays the card type. Also try directly accessing and displaying the card type by adding code in the main method using the form:
<Class name>.<CLASS CONSTANT NAME>

Class Variables

Like class constants, class variables are shared by all objects of the class. The difference is that class variables can be assigned new values and, because of this, we make class variables private so we can protect them from being incorrectly changed by other classes. The typical form for specifying a class variable is:

private static <type> <name>;

Add a class variable to your CreditCard class that is used to keep a count of the number of CreditCard objects that have been constructed. Modify your constructor(s) so that this count is incremented each time the constructor is executed. Note the typical form for accessing class variables within their class is:

<Class name>.<class variable name>

Note that we don't use this but rather we use the class name when accessing class variables. See what happens when you do use this when you increment the count in your constructor.

To access class variables outside of the class we use class methods, which we'll cover next.

Task 6: Class Methods

We can also create class methods to access class variables (or constants) or to implement algorithms that do not require an instance of the class to do their task. Class methods use the reserved word static like class constants and class variables. Note that the main method, which you've been using for your test or driver program, is a class method. In its heading you'll find static.

Add a class method, named getCount, that returns the count of credit cards that have been constructed. Then add code to your main method that constructs several credit card objects and then displays the count of credit cards using your new class method. Note the typical form for calling a class method is:
<Class name>.<class method name>(<arguments>)

Note that class methods cannot access instance variables or instance constants in the way that instance methods can using "this." form. Give this a try. Add to your getCount method the following line of code: this.name = "Test"; and note the compiler error that results.

Task 7: Private Instance Methods

The last thing we'll have you code is a means to generate a security number using a private instance method. You may be aware that on the signature side of a credit card is printed a three digit card verification value (CVV), which sometimes is needed to make a purchase. Note that this number changes each time you're issued a new card for your credit account. We'll generate a two digit security number. Add an integer instance variable to the class for this security code. Then add a method, called computeCVV, that implements the following algorithm (Hint: use mod %):

  1. divide the credit card number by the count of credit cards
  2. the ones (second) digit of the security number is the ones digit of the result in step 1
  3. the tens (first) digit of the security number is the tens digit of the result in step 1
This method is be used to initialize the verification value when a CreditCard object is constructed. Modify your constructor(s) to use this new method. Also add a accessor method to your class that can be used to access the security code. Finish by modifying your driver program to test the verification value implementation.

Challenge Task 1: Unique Card Numbers (Optional)

How can you guarantee that credit cards have unique 16 digit numbers? Modify your class to achieve this requirement. Note the number must have 16 digits (no leading zeros) and must be unique.

Challenge Task 2: Non-ascending Unique Card Numbers (Optional)

How would you generate arbitrary 16 digit numbers that are not in ascending order? Modify your class to achieve this requirement. Note the number must have 16 digits (no leading zeros), must be unique, and must not be in ascending order.