Thursday, February 16, 2012

Generics - Introduction




If the Box class had been designed with generics in mind, this mistake would have been caught by the compiler, instead of crashing the application at runtime.

Introduction

Generics add stability to your code by making more of your bugs detectable at compile time. Some programmers choose to learn generics by studying the Java Collections Framework; after all, generics are heavily used by those classes.

A Simple Box Class

Let's begin by designing a nongeneric Box class that operates on objects of any type. It need only provide two methods: add, which adds an object to the box, and get, which retrieves it:

    public class Box {

        private Object object;

        public void add(Object object) {
            this.object = object;
        }

        public Object get() {
            return object;
        }
    }

Since its methods accept or return Object, you're free to pass in whatever you want, provided that it's not one of the primitive types. However, should you need to restrict the contained type to something specific (like Integer), your only option would be to specify the requirement in documentation (or in this case, a comment), which of course the compiler knows nothing about:


public class BoxDemo1 {

    public static void main(String[] args) {

        // ONLY place Integer objects
        // into this box!
        Box integerBox = new Box();

        integerBox.add(new Integer(10));
        Integer someInteger
            = (Integer)integerBox.get();
        System.out.println(someInteger);
    }
}

The BoxDemo1 program creates an Integer object, passes it to add, then assigns that same object to someInteger by the return value of get. It then prints the object's value (10) to standard output. We know that the cast from Object to Integer is correct because we've honored the "contract" specified in the comment. But remember, the compiler knows nothing about this — it just trusts that our cast is correct. Furthermore, it will do nothing to prevent a careless programmer from passing in an object of the wrong type, such as String:


public class BoxDemo2 {

    public static void main(String[] args) {

        // ONLY place Integer objects
        // into this box!
        Box integerBox = new Box();

        // Imagine this is one part of
        // a large application
        // modified by one programmer.
        // Note how the type is now
        // String.
        integerBox.add("10");

        // ... and this is another,
        // perhaps written by a
        // different programmer
        Integer someInteger
            = (Integer)integerBox.get();
        System.out.println(someInteger);
    }
}

In BoxDemo2 we've stored the number 10 as a String, which could be the case when, say, a GUI collects input from the user. However, the existing cast from Object to Integer has mistakenly been overlooked. This is clearly a bug, but because the code still compiles, you wouldn't know anything is wrong until runtime, when the application crashes with a ClassCastException:

Exception in thread "main"
     java.lang.ClassCastException:
        java.lang.String cannot be cast to java.lang.Integer
        at BoxDemo2.main(BoxDemo2.java:6)





source: The Java Tutorials


No comments: