Advertisements

Java Generics: Part 1

Generics

Generics in Java are an interesting subject. On the one hand, it represent a leap forward in object oriented programming in terms of code reuse and type safety. On the other, it wasn’t quite what we were looking for. If you ask me C# (which is largely derivative of Java) worked out some of the annoying issues with Java’s generics, but if you’re writing code in Java (such as Android apps) you don’t have much choice in the matter. So here I will attempt a brief description of what generics look like in Java and how to do some of the things you never knew you wanted to do.

The Basics

The most basic example for generics is a collection/data structure. These are very common, and are in many ways the original reason why people wanted generics. The idea is simple: I want to make an object that takes a class/type as one of its parameters. For example, if you are making a List class, you will want to code it using a generic type identifier so that list can store any kind of object. To do this, your class declaration will look something like this:

public class TestClass {

}

This is pretty straightforward. Here we are saying, I want to create a class called TestClass that will use some other class T in its implementation, without caring what that type is until runtime.

So what do we do with T? Well really we can do anything with it. We can have member variables, we can make collections, we can declare methods that take instances of T as a parameter, and we can return object of type T. This allows us to forget about what T actually is, and focus more on what we want to do with it. In the case of our List example, chances are we aren’t doing anything other than adding and removing objects, so we don’t really care what T is.

public class TestClass {
	Object[] array;

	public TestClass() {
		array = new Object[10];
	}
}

Notice that we will be storing our values in an Object array. In Java you cannot create an array of a generic type. There are some hacky tricks that allow you to do it, but ultimately they don’t offer you anything of value.

So now we’ve got an object, and we’ve got a place to store our data. Lets add some functionality to our list.

private int count;

public TestClass() {
	array = new Object[10];
	count = 0;
}

public void add(T value) {
	array[count++] = value;
}

We’re going to need to keep track of how many objects are in the list, so we’ll have an instance variable called “count”, and we are going to create a method called add that, you guessed it, adds a value to the list. Notice that value is of type T. Every time a value is added to the array we will advance our count, and the next value will be stored in the next position of the array.

What is going to happen when you add the tenth item? Well as its written it will throw and exception, but we can fix that.

public void add(T value) {
	if (count == array.length) {
		expand();
	}
	array[count++] = value;
}

private void expand() {
	Object[] newArray = new Object[array.length * 2];

	for (int x = 0; x < array.length; x++) {
		newArray[x] = array[x];
	}

	array = newArray;
}

When we run out of space, we will expand our object’s capacity by creating a larger array, copying our values into it, and discarding the old array. This means that our array can potentially expand to become as large as we want it to be.

Now that we can store items in the array, how about getting them out? Since our array has random access, we can forward that behavior to our list.

public T get(int pos) {
	return (T) array[pos];
}

Notice that since array is an Object[], we have to cast the value before returning it. Your editor will probably complain that this is an “unchecked cast” and will want you to use instanceof to check the object’s type before returning it. This however will not work because you cannot read the class of a generic type at runtime. There are all kinds of reasons why this doesn’t work, but the point of it all is: you can’t. So rather than stare at warnings, you can simply put a @SuppressWarnings(“unchecked”) attribute on your method and move on (this just gets rid of the compiler warning).

The final functionality we need is the ability to remove things from the list, which will look something like this:

public void remove(int pos) {
	for (int x = pos; x < array.length - 1; x++) {
		array[x] = array[x+1];
	}
	array[count--] = null;
}

To remove the value at ‘pos’ we need to shift all of the values down by one position and set the last value to null. This can be very expensive if your list is long and you are removing from the front, but then again you can’t remove things from arrays, so who can complain?

Making collections is complex, which is why generally people don’t do it. Java has lots of built in collections, but its always possible you’ll need to extend another.

This of course has been an extremely simple example, but I hope that it helps you understand more about generics and how they can be used.

Advertisements