GenericsJ8 Home « Generics
In this lesson we unravel the terminology behind generics and look at some of the the strange syntax we get with it. Generics were added to Java in 1.5 and are the biggest of all the changes made to the Java language in the 1.5 release. Although generics are not just for collection types the majority of usage is within collections and so here is a good place to talk about generics.
When we talk about generics or a generic type what we are actually talking about is a parameterized type. So a class, interface or method that has has one or more generic types in
its definition can be thought of as generic and we can replace the generic type with a parameterized type. When we define the actual interface, class or method within our code we replace
the formal type parameter with the actual type parameter required. As an example we saw in the Collection Hierarchy Diagram that the List
interface is specified as List<E>
. The following code shows a declaration of an ArrayList<E>
using a polymorphic declaration that will
only except String objects:
package info.java8;
/*
In the following code snippet we replace the formal type parameter E
with an actual type parameter String
*/
List<String> aList = new ArrayList<String>();
So what do generics bring to the party? Even pre 1.5 we could create generalized interfaces, classes or methods by using references of the Object
superclass.
So you will see a lot of generalized pre 1.5 stuff that works on Object
but this approach could not guarantee type safety. The problem being that you
need to cast from Object
to the actual type being worked on.
For instance every time you wanted to read from a collection you would need to cast every object you read. If an object of the wrong type was inserted into the collection then the cast could cause a runtime exception. The exception might be in a program completely removed from the collection itself and might not happen for a long time, making every collection a possible ticking timebomb. The exception to this were Array objects where we have always implicitly declared the type on array creation, so arrays have always been type safe.
With generic type declarations of collections the compiler knows that only objects of the specified type can be added to this collection or throws up a compiler error. Through this mechanism we can achieve type safety for our collections and not have to worry about someone else inputting an invalid object into our collections.
Because of the huge impact generics had on the language the developers at Sun microsystems, the original writers of Java and still in control when 1.5 was released, made the decision to keep raw types in the language. This decision was made so that the billions of lines of code already written in Java were still compatible in Java. So wherever you see generic code in the language you can, although not in any way recommended, use raw types without any parameterisation instead. Before we get into some coding now is a good time to look at the various terminology used in the rest of this lesson:
Term | Examples | Notes |
---|---|---|
Raw Type | List | No parameterization. |
Generic Type | List<E> | An interface, class or method followed by one or more formal type parameters within angled brackets. |
Formal Type parameter | E | One or more formal type parameters delimitied by commas, which can be thought of as placeholders for the actual type parameters. |
Parameterized Type | List<String> | An interface, class or method followed by one or more actual type parameters within angled brackets. |
Actual Type parameter | String | One or more actual type parameters delimitied by commas. Object types are allowed when using generics but primitive types are not. |
Bounded Type | <T extends Number> | Create a superclass boundary which all actual type parameters must be or extend from. |
Unbounded Wildcard Types | List<?> | Unknown type. |
Bounded Wildcard Types | List<? extends Number> | Create a superclass boundary which all unknown types must be or extend from. |
Creating A Folder For Our Collections/Generics Source Files
As we are about to write our first code of a new section we will create a folder for our Collections/Generics files, in Windows this would be:
double click My Computer icon
double click C:\ drive (or whatever your local drive is)
right click the mouse in the window
from the drop down menu Select New
click the Folder option and call the folder _Collections and press enter.
Raw Type/Generic Type Comparison Top
Lets take a look at some non-generic code and the pitfalls associated with type safety and then use some type safe generic code to do the same thing.
Raw Type Example
First we will create a raw type collection where we only want String
objects stored and add an Integer
object:
package info.java8;
/*
Test class for Raw Type Collection
*/
import java.util.*; // Import the java.util package
public class RawTypeNameCollection {
/*
Raw Type name ArrayList containing only String instances
*/
private static final Collection names = new ArrayList();
public static void main (String[] args) {
// Add to our collection
names.add(new String("Bill"));
names.add(new String("Ben"));
// Nothing to stop us adding an Integer
names.add(new Integer(6));
// Now use a raw iterator to iterate over our collection
for (Iterator i = names.iterator(); i.hasNext(); ) {
String aName = (String) i.next(); // ClassCastException (on Integer)
System.out.println(aName); // Print name
}
}
}
Save and compile the RawTypeNameCollection
class in directory c:\_Collections in the usual way.

As you can see the program compiles but the compiler gives us a couple of messages which we ignore at our peril. So recompile the program as suggested with the -Xlint:unchecked
option:

Compiling with the -Xlint:unchecked
option gives us a lot more information contained within the compiler warnings. The compiler is basically telling us we are using non generic code for our
polymorphic Collection
and hence is not type safe. So the compiler has done its job and told us we are using a raw type, but the code is still executable because legacy code is still
allowed. Lets run the code:

As expected we get a ClassCastException
when we iterate over the Integer
object. You can imagine a scenario where our collection is public and accessed elsewhere and the effort involved
to track down the erroneous code.
Generic Type Example
Now we will create a generic type collection where we only want String
objects stored and add an Integer
object:
package info.java8;
/*
Test class for Generic Type Collection
*/
import java.util.*; // Import the java.util package
public class GenericTypeNameCollection {
/*
Generic Type name ArrayList containing only String instances
*/
private static final Collection<String> names = new ArrayList<String>();
public static void main (String[] args) {
// Add to our collection
names.add(new String("Bill"));
names.add(new String("Ben"));
// Now try adding an Integer
names.add(new Integer(6));
// Now use a parameterised type iterator to iterate over our collection
for (Iterator<String> i = names.iterator(); i.hasNext(); ) {
String aName = i.next(); // No cast required
System.out.println(aName); // Print name
}
// Use enhanced for loop to iterate over collection (preferred)
for (String s : names) { // No cast required
System.out.println(s); // Print name
}
}
}
Save and compile the GenericTypeNameCollection
class in directory c:\_Collections in the usual way.

The compile fails when we try to add an Integer to our type safe ArrayList<String>
which is exactly what we want. There is now no chance of getting a ClassCastException
at runtime as the code won't even compile. If our collection was public and someone tried to put in anything else other than String
objects they won't even get a clean compile. Remove the code
that tries to insert the Integer
object and recompile and run the class in the normal way.

We iterate over the loop twice, the first time with a parameterised type iterator and the second time using the enhanced for loop introduced in Java. In neither case do we need to cast as the compiler has already inserted casts for us when compiling the code. Also using the enhanced for loop is much easier to write, more elegant and recommended when iterating over collections.
Generic Interfaces Top
With generics we can create our own generic interfaces which allow us to create generalized interfaces with all the type safety that generics gives us.
Following is a simple generic interface and class so you can see how we can create a generic interface and implement it. We are using T as the placeholder for our formal type parameter in this instance.; which you can think of as a pneumonic for Type. In the collections example above we used the E pneumonic for Element. When creating your own generic types it is best parctice to use pneumonics for the formal type parameter rather than multiple letters.
In the overridden showObjectType()
method we are using the getClass()
method of Object
to get the actual Class type which we chain to getName()
, which is a method of the Class
object, which can be found in the java.lang
package and print this to the console.
Notice how we use the T formal type parameter within the declaration and constructor.
package info.java8;
/*
Simple generic interface that accepts any object
*/
interface SimpleGenericInterface<T> {
// Implementation will show object type
void showObjectType();
}
/*
Simple generic class that implements SimpleGenericInterface
*/
public class SimpleGenericInterfaceImpl<T> implements SimpleGenericInterface<T> {
// Generic object declaration
T genericObj;
// Pass reference to object of type T to our constructor
SimpleGenericInterfaceImpl(T genericObj) {
this.genericObj = genericObj;
}
// Output object type of T to console
public void showObjectType() {
System.out.println("Object type of T is " + genericObj.getClass().getName());
}
}
Save and compile the SimpleGenericInterface
interface and SimpleGenericInterfaceImpl
class in directory c:\_Collections in the usual way.

Now we need to write a test class to show how we can pass various objects to our SimpleGenericInterfaceImpl
class:
package info.java8;
/*
Test our SimpleGenericClass class that accepts any object
*/
public class TestSimpleGenericInterfaceImpl {
public static void main(String args[]) {
// Test the SimpleGenericInterfaceImpl using a String object
SimpleGenericInterfaceImpl<String> genStringObj = new SimpleGenericInterfaceImpl<String>("ab");
genStringObj.showObjectType();
// Test the SimpleGenericInterfaceImpl using an Integer object
SimpleGenericInterfaceImpl<Integer> genIntegerObj = new SimpleGenericInterfaceImpl<Integer>(1);
genIntegerObj.showObjectType();
// Test the SimpleGenericInterfaceImpl using a Double object
SimpleGenericInterfaceImpl<Double> genDoubleObj = new SimpleGenericInterfaceImpl<Double>(1.2);
genDoubleObj.showObjectType();
}
}
Save, compile and run the TestSimpleGenericInterfaceImpl
class in directory c:\_Collections in the usual way.

So from the screenshot you can see that our TestSimpleGenericClass
class works with the various objects passed to it replacing the T formal type parameter placeholder with the actual type parameter
of the object passed. We mentioned ealier that the compiler inserts the casts required to make generics work when we run our bytecode. What we haven't mentioned yet is that generic code is implemented
by erasure, which means that generic code enforces type constraints only at compile time. The element type information is erased in the runtime bytecode, which is how legacy code can freely
interoperate with generic code. So the point here is that at runtime there is only one version of the SimpleGenericInterfaceImpl
class that works through the casts inserted automatically by the
compiler into the runnable bytecode.
Generally if a class implements a generic interface then that class must be generic as well, so that it takes a type parameter that is passed to the interface. If an actual parameter is used when implementing the interface, then the class doesn't have to be generic. The following code snippet should clarify this:
package info.java8;
// Following is correct as used above
public class SimpleGenericInterfaceImpl<T> implements SimpleGenericInterface<T> {
// Following is incorrect as no type specifed for class and formal type parameter specified
public class SimpleGenericInterfaceImpl implements SimpleGenericInterface<T> {
// Following is fine as actual type specified for implementation, so class is not generic
public class SimpleGenericInterfaceImpl implements SimpleGenericInterface<String> {
Generic Classes Top
With generics we also have the option to create our own generic classes which allow us to create generalized classes in much the same way as using an Object
reference but with all the type safety that generics gives us.
Following is a simple generic class so you can see how we can create a generic class. We are using T as the placeholder for our formal type parameter in this instance.
We are using the getClass()
method of Object
to get the actual Class type
which we chain to getName()
, which is a method of the Class
object, which can be found in the java.lang
package and print this to the console. Notice how we use the
T formal type parameter within the declaration, constructor and getGenericObj()
getter method.
package info.java8;
/*
Simple generic class that accepts any object
*/
public class SimpleGenericClass<T> {
// Generic object declaration
T genericObj;
// Pass reference to object of type T to our constructor
SimpleGenericClass(T genericObj) {
this.genericObj = genericObj;
}
// Output object type of T to console
void showObjectType() {
System.out.println("Object type of T is " + genericObj.getClass().getName());
}
// Return the generic object
T getGenericObj() {
return genericObj;
}
}
Save and compile the SimpleGenericClass
class in directory c:\_Collections in the usual way.

Now we need to write a test class to show how we can pass various objects to our SimpleGenericClass
class:
package info.java8;
/*
Test our SimpleGenericClass class that accepts any object
*/
public class TestSimpleGenericClass {
public static void main(String args[]) {
// Test the SimpleGenericClass using a String object
SimpleGenericClass<String> genStringObj = new SimpleGenericClass<String>("A stitch in time");
genStringObj.showObjectType();
String str = genStringObj.getGenericObj();
System.out.println("String value is: " + str);
// Test the SimpleGenericClass using an Integer object
SimpleGenericClass<Integer> genIntegerObj = new SimpleGenericClass<Integer>(123);
genIntegerObj.showObjectType();
int i = genIntegerObj.getGenericObj();
System.out.println("Integer value is: " + i);
// Test the SimpleGenericClass using a Double object
SimpleGenericClass<double> genDoubleObj = new SimpleGenericClass<double>(123.456);
genDoubleObj.showObjectType();
double d = genDoubleObj.getGenericObj();
System.out.println("Double value is: " + d);
}
}
Save and compile the TestSimpleGenericClass
class in directory c:\_Collections in the usual way.

As you can see from the screenshot we got an error. As mentioned in our terminology table above you can't use primitive types with generics. So correct the code by changing the double
generic type
and actual parameter type to Double
for the genDoubleObj
instantiation.
Save, compile and run the TestSimpleGenericClass
class in directory c:\_Collections in the usual way.

So from the screenshot you can see that our TestSimpleGenericClass
class works with the various objects passed to it replacing the T formal type parameter placeholder with the actual type parameter
of the object passed.
Bounded Types Top
Generics are by design invariant, which means for any two distinct types Type1
and Type2
, List<Type1>
is neither a supertype or subtype
of List<Type2>
. The following code snippet should help with understanding of this statement:
package info.java8;
/*
Generics are invariant
*/
List<Object> aList = new ArrayList<String>(); // Invalid
List<String> aList = new ArrayList<String>(); // Valid
You would think that because String
like all objects extends Object
that the first statement is prefectly valid, but generics doesn't work like polymorphic types because of invariance.
So the simple rule here is that the reference type must always match the actual object type when using generics.
But say for instance we want to create a generic class that uses subclasses of the Number
class to do some mathematical calculations. How do we get the different types to work? First lets look at generic invariance by writing a class:
package info.java8;
/*
Generic type invariance
*/
public class BoundedTypeClass<T> {
// Generic object declaration
T genericNumberObj;
// Pass reference to object of type T to our constructor
BoundedTypeClass(T genericNumberObj) {
this.genericNumberObj = genericNumberObj;
}
// Return the square of the integer
double squareInt() {
return genericNumberObj.intValue() * genericNumberObj.intValue();
}
// Return the square of the fraction
double squareDbl() {
return genericNumberObj.doubleValue() * genericNumberObj.doubleValue();
}
}
Save and compile the BoundedTypeClass
class in directory c:\_Collections in the usual way.

The compiler has no way of knowing we are only passing numeric types and we want to use subclasses of Number
. Luckily for us Java generics come with bounded types which allows us to specify
a superclass boundary which our formal type parameters must be or extend from. So in our case we need to change our generic type from <T>
to <T extends Number>
.
This is now telling the compiler that our formal type parameter of <T>
must either be a Number
or a subclass thereof. Lets modify our class declaration to do this:
package info.java8;
/*
Generic type invariance
*/
public class BoundedTypeClass<T extends Number> { // Bounded Type
// Generic object declaration
T genericNumberObj;
// Pass reference to object of type T to our constructor
BoundedTypeClass(T genericNumberObj) {
this.genericNumberObj = genericNumberObj;
}
// Return the square of the integer
double squareInt() {
return genericNumberObj.intValue() * genericNumberObj.intValue();
}
// Return the square of the fraction
double squareDbl() {
return genericNumberObj.doubleValue() * genericNumberObj.doubleValue();
}
}
Save and compile the BoundedTypeClass
class in directory c:\_Collections in the usual way.

The program compiles fine now and will only allow subclasses of the Number
to use our class. We need to write a test class to show how we can pass various subclasses of
Number
to our BoundedTypeClass
class and nothing else:
package info.java8;
/*
Test our BoundedTypeClass class that only accepts Number subclasses
*/
public class TestBoundedTypeClass {
public static void main(String args[]) {
// Test the BoundedTypeClass using an Integer object
BoundedTypeClass<Integer> genIntegerObj = new BoundedTypeClass<Integer>(12);
System.out.println("Square of genIntegerObj is: " + genIntegerObj.squareInt());
System.out.println("Fractional Square of genIntegerObj is: " + genIntegerObj.squareDbl());
// Test the BoundedTypeClass using a Double object
BoundedTypeClass<Double> genDoubleObj = new BoundedTypeClass<Double>(12.12);
System.out.println("Square of genDoubleObj is: " + genDoubleObj.squareInt());
System.out.println("Fractional Square of genDoubleObj is: " + genDoubleObj.squareDbl());
// Test the BoundedTypeClass using a String object
BoundedTypeClass<String> genStringObj = new BoundedTypeClass<String>("A stitch in time");
System.out.println("Square of genStringObj is: " + genStringObj.squareInt());
System.out.println("Fractional Square of genStringObj is: " + genStringObj.squareDbl());
}
}
Save and compile the TestBoundedTypeClass
class in directory c:\_Collections in the usual way.

As you can see from the screenshot we got a compiler error for the String
object as this doesn't extend Number
which is what we would expect. So remove the comment and last three
statements for the String
invocation of the BoundedTypeClass
class from the main()
method.
Save, compile and run the TestBoundedTypeClass
class in directory c:\_Collections in the usual way.

So from the screenshot you can see that our BoundedTypeClass
class works with subclasses of the Number
object due to our use of bounded types.
Unbounded Wildcard Types Top
We saw how we can use unbounded types to get around the problem with invariance above. Lets extend our BoundedTypeClass
class to compare the actual integer values of objects passed in to
see if they are equal.
package info.java8;
/*
Generic type invariance
*/
public class BoundedTypeClass<T extends Number> { // Bounded Type
// Generic object declaration
T genericNumberObj;
// Pass reference to object of type T to our constructor
BoundedTypeClass(T genericNumberObj) {
this.genericNumberObj = genericNumberObj;
}
// Return the square of the integer
double squareInt() {
return genericNumberObj.intValue() * genericNumberObj.intValue();
}
// Return the square of the fraction
double squareDbl() {
return genericNumberObj.doubleValue() * genericNumberObj.doubleValue();
}
// Return true if integer values of two objects are equal
boolean intEqual(BoundedTypeClass<T> obj) { // Input T type
if (genericNumberObj.intValue() == obj.genericNumberObj.intValue()) {
return true;
} else {
return false;
}
}
}
Save and compile the BoundedTypeClass
class in directory c:\_Collections in the usual way.

The program compiles fine, so now we need to write a test class to see if everything still works and we can compare integer values:
package info.java8;
/*
Test our BoundedTypeClass class that only accepts Number subclasses
*/
public class TestBoundedTypeClass {
public static void main(String args[]) {
// Test the BoundedTypeClass using an Integer object
BoundedTypeClass<Integer> genIntegerObj = new BoundedTypeClass<Integer>(12);
System.out.println("Square of genIntegerObj is: " + genIntegerObj.squareInt());
System.out.println("Fractional Square of genIntegerObj is: " + genIntegerObj.squareDbl());
// Test the BoundedTypeClass using another Integer object
BoundedTypeClass<Integer> genIntegerObj2 = new BoundedTypeClass<Integer>(13);
System.out.println("Square of genIntegerObj2 is: " + genIntegerObj2.squareInt());
System.out.println("Fractional Square of genIntegerObj2 is: " + genIntegerObj2.squareDbl());
// Test the BoundedTypeClass using a Double object
BoundedTypeClass<Double> genDoubleObj = new BoundedTypeClass<Double>(12.12);
System.out.println("Square of genDoubleObj is: " + genDoubleObj.squareInt());
System.out.println("Fractional Square of genDoubleObj is: " + genDoubleObj.squareDbl());
// Test the BoundedTypeClass using another Double object
BoundedTypeClass<Double> genDoubleObj2 = new BoundedTypeClass<Double>(13.13);
System.out.println("Square of genDoubleObj2 is: " + genDoubleObj2.squareInt());
System.out.println("Fractional Square of genDoubleObj2 is: " + genDoubleObj2.squareDbl());
// Test integer equality of objects
if (genIntegerObj.intEqual(genIntegerObj2)) {
System.out.println("Integer values are equal");
} else {
System.out.println("Integer values are not equal");
}
if (genDoubleObj.intEqual(genDoubleObj2)) {
System.out.println("Integer values are equal");
} else {
System.out.println("Integer values are not equal");
}
if (genIntegerObj.intEqual(genDoubleObj)) {
System.out.println("Integer values are equal");
} else {
System.out.println("Integer values are not equal");
}
}
}
Save and compile the TestBoundedTypeClass
class in directory c:\_Collections in the usual way.

As you can see from the screenshot we got a compiler error for the call to the intEqual()
method. In the first two calls to the intEqual()
method the invoking and parameter object
are the same and so there is no problem. In the last call we have an invoking object of Integer
and a parameter object of Double
and as the compiler error points out we cant convert
the latter bounded class type to the former. We need a way to let the compiler know that the input parameter, which we know can only be instantiated as a Number
object or subclass
thereof is an unknown type. We can achieve this by using an unbounded wildcard type, which is specified using the ?
symbol, as the input parameter to the intEqual()
method of
the BoundedTypeClass
class.
Change the signature to boolean intEqual(BoundedTypeClass<?> obj)
and recompile the BoundedTypeClass
class.
Save,compile and run the TestBoundedTypeClass
class in directory c:\_Collections in the usual way.

The BoundedTypeClass
class now works as shown in the screenshot through our use of an unbounded wildcard type.
Bounded Wildcard Types Top
We saw how we can use unbounded types to get around the problem with invariance and we then looked at how to allow an unknown type by using unbounded wildcard types. What if we had a scenario where we only want a method to work on a particular clas or subclasses of it? For this type of situation we can use bounded wildcard types to only allow certain classes to use a method. Ok, lets start by creating and compiling some simple classes:
package info.java8;
public class A {
{
System.out.println("A Object initializer");
}
}
public class B extends A {
{
System.out.println("B Object initializer");
}
}
public class C extends B {
{
System.out.println("C Object initializer");
}
}
public class D { // Nothing to do with other classes
{
System.out.println("D Object initializer");
}
}
Save and compile the A
, B
, C
and D
classes in directory c:\_Collections in the usual way.

Now we need to write a simple generic class that will take any type and haev a method within in that will eventually only work on the A
class and subclasses of it; but first we will let
the method work with any type:
package info.java8;
/*
Simple generic class that accepts any object
*/
public class BoundedWildcardType<T> {
// Generic object declaration
T genericObj;
// Pass reference to object of type T to our constructor
BoundedWildcardType(T genericObj) {
this.genericObj = genericObj;
}
// Output object type of BoundedWildcardType to console
void showObjectType(BoundedWildcardType obj) {
System.out.println("Object type of BoundedWildcardType is " + genericObj.getClass().getName());
}
}
Save and compile the BoundedWildcardType
class in directory c:\_Collections in the usual way.

Now we need to write a test class to show how we can pass various objects to our BoundedWildcardType
class:
package info.java8;
/*
Test our BoundedWildcardType class that accepts any object
*/
public class TestBoundedWildcardType {
public static void main(String args[]) {
// Create some objects
A a = new A();
B b = new B();
C c = new C();
D d = new D();
// Test the BoundedWildcardType using A, B, C and D objects
BoundedWildcardType<A> genAObj = new BoundedWildcardType<A>(a);
genAObj.showObjectType(genAObj);
BoundedWildcardType<B> genBObj = new BoundedWildcardType<B>(b);
genBObj.showObjectType(genBObj);
BoundedWildcardType<C> genCObj = new BoundedWildcardType<C>(c);
genCObj.showObjectType(genCObj);
BoundedWildcardType<D> genDObj = new BoundedWildcardType<D>(d);
genDObj.showObjectType(genDObj);
}
}
Save, compile and run the TestBoundedWildcardType
class in directory c:\_Collections in the usual way.

Well nothing new here, all the classes run as expected. Now we want to change the BoundedWildcardType
class so that only objects of type A
or sublasses thereof can use the
showObjectType(BoundedWildcardType obj)
method and for this we need a bounded wildcard type.
Change the signature to showObjectType(BoundedWildcardType<? extends A> obj)
and recompile the BoundedTypeClass
class.
Save and compile the TestBoundedTypeClass
class in directory c:\_Collections in the usual way.

As you can see from the screenshot above the compiler won't allow us to call the showObjectType(BoundedWildcardType<? extends A> obj)
method with an object of class D
because
the method now has an unbounded wildcard type that only allows the A
class and its subclasses.
Remove the creation and call for the genDObj
in the TestBoundedTypeClass
class and save,compile and run the class in directory c:\_Collections in the usual way.

The BoundedWildcardType
class now works as shown in the screenshot through our use of an unbounded wildcard type.
Generic Methods Top
We have seen several examples of generic methods so far in this lesson and these were all contained within genric classes. It is also possible to have generic methods inside non-generic classes.
Following is a non-generic class that contains a generic method. Two things of note are generic methods can be static or non-static and notice where we declare the bounded type. When declaring a generic method in a non-generic class then we have to declare the generic type before the return type within the method:
package info.java8;
/*
Non-generic class containing a generic method
*/
public class SquareNumber{
public static void main (String[] args) {
Double d = new Double(12.12);
genMethod(d);
Integer i = new Integer(11);
genMethod(i);
String s = new String("generics");
genMethod(s);
}
/*
Method to print square of integer
*/
static <T extends Number> void genMethod (T number) {
System.out.println("Input squared as integer = " + number.intValue() * number.intValue());
}
}
Save and compile the SquareNumber
class in directory c:\_Collections in the usual way.

The compile files which it should do as the String
object does not extend number. So remove the last 2 lines of code from the main() and save, recompile and run the
SquareNumber
class.

As the screenshot shows the method now works fine and will only except Number
objects and its subclasses.
Generic Constructors Top
We have seen several examples of generic constructors so far in this lesson and these were all contained within genric classes. It is also possible to have generic constructors inside non-generic classes.
Following is a non-generic class that contains a generic constructor. Notice where we declare the bounded type. When declaring a generic constructor in a non-generic class then we have to declare the generic type before the constructor name:
package info.java8;
/*
Non-generic class containing a generic constructor
*/
class CubeNumber {
private int cubedNumber;
// Pass bounded type to our constructor
<T extends Number> CubeNumber(T number) {
cubedNumber = number.intValue() * number.intValue() * number.intValue();
}
// getter for cubed number
public int getNumber() {
return cubedNumber;
}
}
Save and compile the CubeNumber
class in directory c:\_Collections in the usual way.

Now we need to write a test class to show how we can pass various Number
objects to our CubeNumber
class:
package info.java8;
/*
Test our CubeNumber class that accepts Number and subclasses for its constructor
*/
public class TestCubeNumber {
public static void main(String args[]) {
// Test the CubeNumber using an Integer object
CubeNumber integerObj = new CubeNumber(12);
System.out.println("Input cubed = " + integerObj.getNumber());
// Test the CubeNumber using a Double object
CubeNumber doubleObj = new CubeNumber(13.45);
System.out.println("Input cubed = " + doubleObj.getNumber());
}
}
Save, compile and run the TestCubeNumber
class in directory c:\_Collections in the usual way.

So from the screenshot you can see that our TestSimpleGenericClass
class works with the various objects passed to the constructor replacing the T formal type parameter placeholder with
the actual type parameter of the object passed.
Lesson 2 Complete
In this lesson we looked at generics and how to use them.
What's Next?
In the next lesson we look at Sets, as these are probably the easiest collection type to understand and as such a good starting point.
<