In this lab, you will work with Java methods.
In this lab, you will work with a PoolEntry class that represents an entry in an office "sports pool". (You may recall writing a calcBonus method in an earlier lab -- you will make use of that method in this lab, too.) To save time, we will provide you with some partially completed code that you will import into a project. Follow these steps:
Create a new project named Lab06.
Right-click on the new project's src folder and choose Import.
On the first wizard page, choose General - File System, then press Next.
For the From directory, browse to the {Lab Installation Directory}/starters/lab06 folder, then press OK.
Select the pool and test folders (see Figure 1) and then press Finish.
Note: After importing, you should have no errors.

Examine the imported pool.PoolEntry class and note how it represents a an entry in a sports pool. Then examine the imported test.TestPoolEntry class and note how it creates a few PoolEntry objects and initializes its fields using "set" methods.
Edit the PoolEntry class and write a public constructor method that accepts parameters that match all of the fields in the class. Remember that constructor methods have the same name as the class and have no return value.
Implement the method by assigning each parameter to the corresponding field. Remember that you can use the this reference, for example:
public PoolEntry ( int entrantID,
Date entryDate,
int predictedTeam1,
int predictedTeam2,
int actualTeam1,
int actualTeam2)
{
this.entrantID = entrantID;
. . .
}
Save PoolEntry.java and note that you now have errors in TestPoolEntry!
That's because TestPoolEntry is using PoolEntry's built-in, no-argument constructor -- remember that Java gives you that constructor if you don't define ANY constructors. But once you define any constructor, Java "takes" the built-in constructor away.
There are a couple of ways we could fix this. One way would be to recode the "test" classes to use the new, 6-argument constructor. However, let's take a different tack.
Edit PoolEntry and write a new constructor that accepts zero-arguments. This constructor should assign a random number for the entrantID:
public PoolEntry()
{
java.util.Random r = new java.util.Random();
this.entrantID = r.nextInt();
}
After you save, the compilation errors should disappear.
Modify the TestPoolEntry class so that the first object instantiation uses the 6-argument constructor. You can use any entrantID you want, and use new java.util.Date() for the entrantDate.
Note that since you supplied all of that object's state in the constructor, the set methods are redundant for that object. You can comment them out.
Save, run and test that the program works.
You may have noticed that the objects created with the zero-argument constructor have a null entry date. That's because we didn't initialize the field, and Java assigns null to object references by default.
Modify the zero-argument constructor to assign a default date, then run and test.
Write a new constructor that accepts 4 arguments -- this constructor should omit the entryDate and entrantID fields.
To implement the new constructor, call the zero-argument constructor and then initialize the remaining fields:
public PoolEntry (
int predictedTeam1,
int predictedTeam2,
int actualTeam1,
int actualTeam2)
{
this();
this.predictedTeam1 = predictedTeam1;
this.predictedTeam2 = predictedTeam2;
this.actualTeam1 = actualTeam1;
this.actualTeam2 = actualTeam2;
}
Then modify TestPoolEntry so that the second object instantiation uses the 4-argument constructor. Again, you can comment out redundant set methods. Save, run and test.
Write another 4-argument constructor that omits the entrantDate and the actualTeam2 fields. Don't implement it yet -- save the file after you write the constructor method signature.
The reason this cannot compile is that you would have two constructors that have the exact same number and types of parameters, and that's illegal because it is ambiguous. (Remember that the compiler doesn't really care what NAMES you assign to parameters -- it's their type and order that determines the method signature.)
Comment out this 4-argument constructor to get rid of the compile errors.
Static fields are considered to be part of the runtime existence of a class, not as part of individual objects. Even though you might create many objects, there's only one "class object" at runtime -- this enables us to use static fields to share data among all of the objects of a class.
In the last part, since you defined the random number generator object reference as a local variable within the constructor, each object created its own generator object, used it to retrieve a random number, and then allowed the generator object to be garbage collected. The program would be more efficient if the program created a single generator object and shared it amongst the instances.
To share the object, we will define the generator object reference as a static field.
Modify the PoolEntry class so that the Random object is defined as a static field instead of being a local variable in the zero-argument constructor:
private static java.util.Random r = new java.util.Random();
This initialization runs before the first PoolEntry object is created.
The zero-argument constructor should still call the nextInt method and assign it to the entrantID, but be sure to delete the new within the constructor or comment it out.
Save, run and test -- the program should work as before. The new version is more efficient, but the change is probably not noticable to the human eye.
Like static fields, static methods are considered part of the class, not part of any individual object. Often, we write static methods to manipulate static fields.
One side-effect of a method being static is that you don't need to first create an object before calling it -- in an earlier lab, you used the Integer.parseInt() method, which is a good demonstration of a static method.
In this part, you will experiment with static methods.
Create a new class named MyStatic in the mystatic package. This class should not have main method.
Define the following fields:
private int myInt = 42;
private static int myStaticInt = 43;
Write the following methods:
public int getMyInt()
{
return myInt;
}
public static int getMyStaticInt()
{
return myStaticInt;
}
Create a new class named TestStatic in the test package. The new class should have a main method.
In main, write code to call the static method and display its result to the console:
System.out.println(MyStatic.getMyStaticInt());
Note that you don't need to create an object! (You will need to import the MyStatic class.)
Write code in main, in the normal fashion, to create a MyStatic object, call the non-static method and print the result:
MyStatic mys = new MyStatic();
System.out.println(mys.getMyInt());
Note the difference -- to call a static method, you don't need to first create an object. Instead, you use the class name before the dot.
Edit the MyStatic class. In the static method, add this line:
System.out.println(myInt);
Save the file to compile it.
This results in a compilation error because static methods are NOT part of any individual object, and thus cannot access instance fields. This becomes very clear if you think about the code you wrote in TestMyStatic -- you were able to call the static method before ever creating an object! In other words, there were no instance fields in memory at that point in time.
Comment out the offending line before continuing.
Add the following line to the non-static method:
System.out.println(myStaticInt);
Save the file to compile it. This is OK since static fields are considered to be global to all instances. In other words, any instance can access the static fields, since the "class object" is in memory before any instances are created.
One useful application of a static methods and fields is to implement a class of which there can be but a single instance. This design pattern, known as Singleton is what you will implement in this part. You will convert the EntryList class to implement the Singleton pattern using a static field and method.
Edit the EntryList class and write a private zero-argument constructor. You don't need to put any code in the constructor body for now.
Save the file and note that there is now an error in the TestPoolEntry class, which tries to use the zero-argument constructor.
In fact, there is now no way to create an EntryList object from outside of the class, since the only constructor is private! We will address this issue in a moment.
Add a private, static field to the EntryList class:
private static EntryList theInstance;
Add a public, static method that manipulates this field:
public static EntryList getInstance()
{
if (theInstance == null)
theInstance = new EntryList();
return theInstance;
}
This publicly available static method returns the single instance of the class and is the only way for the outside world to obtain that instance. Note that it uses a technique referred to as lazy initialization -- it only instantiates that object the first time it's asked for.
Modify the TestEntryList class to use the static getInstance method.
Save, run and test. Even if we had multiple testing programs running, they would all use the same EntryList object.
In this part, you will practice the techniques covered in this lab to reinforce the concepts.
Create a new class named AutoPolicy in the policy package. This class should not have a main method.
Add the following fields to the class to represent information about an automobile insurance policy. Use types as you feel are appropriate:
policyNumber
policyDate
amount
customerID
Override toString and return an appropriately labeled String.
Write three public constructors in the class:
Create a new class named TestPolicy in the test package with a main method.
Add code in main to create three AutoPolicy objects, each with a different constructor. Print the contents of each object to the console.
Save, run and test.