CS-151 Labs > Lab 2. Object-Oriented Programming
Warmup
In this warmup, we’re going to create and use arrays. Java arrays behave similarly to lists in Python except Java arrays have a fixed size and they’re homogeneous, meaning all elements must have the same type.
Open Eclipse and create a new project called lab2
.
Select the previously created folder cs151/lab2
as a place to store all the lab2
project files.
Add file readme.txt
to the project.
In this file document your warmup experiences: add the name of your lab partner, answer the questions,
and give your overall feedback on the difficulty of the warmup. Later on you will add notes about your lab2 programs, and the Honor pledge.
Playing with Arrays
Create a new class called Arrays
in the warmup2
package with a main
method.
Inside main
, allocate a new array of int
s of length 15.
int[] arr = new int[15];
We can access the elements of the array as arr[0]
, arr[1]
,… Write a
for
loop that prints out each element of the array.
for (int i = 0; i < 15; i++) {
// Replace this comment with code to print out arr[i] here
}
Before running your code: with your partner, try to predict what will be printed. Now, run your code and examine the output before moving on.
Okay, having done that, you’ve surely noticed that it printed the same value 15 times. Now, change just the line
int[] arr = new int[15];
to
int[] arr = new int[10];
Discuss what will happen with your partner and then run your code to check.
In retrospect, this result was entirely predictable. We changed the size of the array, but did not change the bounds of the loop. And this is what happens when we try to access an element of our array that is outside the area allocated to hold array elements.
The problem is that we hard coded the length 15 in the for
loop. We
shouldn’t have done that. Fortunately, as we saw in the past labs, we can get the length of
an array arr
by using arr.length
. Go ahead and change the bound of the
for
loop to be i < arr.length
and rerun your code. Much better!
Let’s try reading some int
s from the user and storing them in an array.
Recall from last lab that we can use a Scanner
to read int
s using the
nextInt()
method. We can read from the command line by creating a new scanner and
then calling nextInt()
for each integer we want.
Scanner scanner = new Scanner(System.in);
int num1 = scanner.nextInt();
int num2 = scanner.nextInt();
Create such a scanner. Ask the user how many numbers they want to enter. Read
the integer by calling scanner.nextInt()
. Now use that integer as the size
of our array rather than our hard coded value 10.
Next, change the loop from
printing out the values of arr[i]
to instead prompting the user to enter a
number, read the number using scanner.nextInt()
and store it in the array at
index i
. We can store a value x
into an array arr
at index i
, using
arr[i] = x;
.
After taking in all the int values, write another for
loop to print out all of the elements of the array in reverse order.
Here’s a sample run of the program:
How many numbers do you want to enter? 3
Enter an int: 10
Enter an int: 20
Enter an int: 30
30
20
10
Extending an abstract class
We’re now going to put our array practice to work by implementing a Set.
A Set is a data type used for storing a collection of different things. Unlike in a sequence of values that we dealt with so far, in a Set the position of each element does not matter, and all elements are unique.
Start by creating a new Java class called AbstractSet
in the warmup2
package.
Copy the following code into the new file, replacing what Eclipse generated for you.
package warmup2;
public abstract class AbstractSet<E> {
/// Returns the number of elements in the set.
public abstract int size();
/// Adds an element e to the set.
public abstract void add(E e);
/// Remove an element e from the set, if it exists.
public abstract void remove(E e);
/// Returns true if e is contained in the set.
public abstract boolean contains(E e);
/// Returns the elements of the set as an array.
public abstract Object[] toArray();
/// Returns a string representation of the set.
public String toString() {
StringBuilder sb = new StringBuilder("{");
Object[] data = this.toArray();
for (int i = 0; i < data.length; i++) {
if (i > 0)
sb.append(", ");
sb.append(data[i].toString());
}
sb.append("}");
return sb.toString();
}
}
Spend a minute or two looking over this code.
Note that the class is declared with public abstract class
rather than
public class
. This indicates that this class cannot be
instantiated directly. Some of its methods are marked abstract
. Any
class which extends AbstractSet
will have to implement these methods.
One of the methods, toString()
is not marked as abstract
and it has a
complete implementation. If you look carefully at the implementation of
toString()
, you’ll see that it works by calling the toArray()
abstract
method and then building a string based on this array.
Let’s now write a new class which extends AbstractSet
and implements the Set
data type using an array. Create a new class named Set
in the same package. Change the
superclass from java.lang.Object
to AbstractSet
and make sure
“inherited abstract methods” is checked. This will create the class for us
with stub methods but it gets a few things wrong. So let’s fix them up.
First, we want our new Set
to be generic, meaning we should be able to
create a set to hold elements of any data type. Our AbstractSet
was also generic so this will work
out well. Change the class declaration to
public class Set<E> extends AbstractSet<E>
In the add()
, remove()
, and contains()
methods, change Object
to E
.
Next, we need to add a constructor to create a new Set
as well some private
instance variables to hold the contents of our set and some metadata about it.
With your partner, think about what information a Set
object needs to
contain. What information about the set will it need to hold? Document the answers in the readme
file.
Hopefully, you decided that we need to store the actual elements of the set in some way. We’re going to use an array for this. But that’s not enough! We’ll need to keep track of how many actual elements are in our set.
We need to store these two pieces of information in each instance of Set
. To
that end, add two private instance variables
private Object[] data;
private int size;
Note that we made data
an array of Object
s rather than an array of
E
—the type of our elements. That’s because Java does not allow to create an
array of generic types so we use the base class Object
instead. We could do this without breaking type safety, because we actually never return the entire array and the array of objects is used only for printing.
Now, we need a constructor.
public Set(int capacity) {
}
Go ahead and fill the constructor out by setting this.data
to a new array of
Object
s of size capacity
and this.size
is already initialized to 0, which means that we don’t currently
have any elements in our set.
With your partner, implement the rest of the methods.
Here are a few hints.
- For
add()
, use afor
loop to walk through the list and usee.equals(this.data[i])
to check ife
already appears in the set. If it does, do nothing - just return. Otherwise, you should check if there’s enough space to adde
to the array. Placee
into the available spot at the end and updatesize
. If there is no space,throw new UnsupportedOperationException("Out of space");
. - For
remove()
, use afor
loop to check ife
is in the array. If so, remove it by moving elements from later in the array one spot earlier (to the left). Updatesize
. - For
toArray()
, create a new array ofObject
s of sizethis.size
. Fill the array by copying allthis.size
elements into the new array and return it.
Finally, let’s write some code to test this out. Create main
method in the Set
class.
Inside the main
create a new Set
of Integer
s, add some elements to it, remove some,
check if some are in the list. And try printing the set. Here’s some sample
code.
AbstractSet<Integer> nums = new Set<Integer>(10);
nums.add(10);
nums.add(10);
nums.add(15);
nums.add(20);
nums.add(15);
System.out.println(nums.contains(10));
nums.remove(10);
System.out.println(nums.contains(10));
nums.add(32);
nums.add(16);
System.out.println("There are " + nums.size() + " elements");
System.out.println(nums);
When run, you should see the following output.
true
false
There are 4 elements
{15, 20, 32, 16}
Try creating different sets using different types. E.g., Set<Double>
or even Set<Set<String>>
.