Upper Bounded Wildcard TypeS2C Home « Upper Bounded Wildcard Type

We saw how we can use a Bounded Type to get around the problem with invariance and we then looked at how to allow an unknown type by using an Unbounded Wildcard Type in the previous two lessons.

What if we had a scenario where we only want a method to work on a particular class or subtypes or supertypes thereof? For this type of situation we can use bounded wildcard types to only allow certain types to use an identifier.

The table below lists the bounded wildcard types we can use with examples.

Bounded Wildcard Types
Term Examples Notes Lesson
Upper Bounded Wildcard TypeList<? extends Number>Create a superclass boundary which all unknown types must be, or subtypes thereof.This lesson
Lower Bounded Wildcard TypeList<? super Integer>Create a subclass boundary which all unknown types must be, or supertypes thereof.Lower Bounded Wildcard Type

Lets look at a code example of using the upper bounded wildcard type.

Ok, lets start by creating and building some simple classes:


package com.server2client;

public class A { 
    {
        System.out.println("A Object initializer"); 
    }
}


package com.server2client;

public class B extends A { 
    {
        System.out.println("B Object initializer"); 
    }
}


package com.server2client;

public class C extends B {    
    {
        System.out.println("C Object initializer"); 
    }
}


package com.server2client;

public class D { // Nothing to do  with other classes    
    {
        System.out.println("D Object initializer"); 
    }
}

Build the classes in the usual way.

Now we need to write a simple generic class that will take any type and have 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 com.server2client;

/*
  Simple generic class that accepts any object
*/
public class UpperBoundedWildcardType<T> {

    // Generic object declaration
    private final T genericObj;

    // Pass reference to object of type T to our constructor
    public UpperBoundedWildcardType(T genericObj) {
        this.genericObj = genericObj;
    }

    // Output object type of UpperBoundedWildcardType to console 
    public void showObjectType(UpperBoundedWildcardType<T> obj) {
        System.out.println("Object type of UpperBoundedWildcardType is " + genericObj.getClass().getName());
    }
}

Building the UpperBoundedWildcardType class produces the following output:

Build upper bounded wilcard type class
Screenshot 1. Building the UpperBoundedWildcardType class.

Now we need to write a test class to show how we can pass various objects to our BoundedWildcardType class:


package com.server2client;

/*
  Test our UpperBoundedWildcardType class that accepts any object
*/
public class TestUpperBoundedWildcardType {

    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 UpperBoundedWildcardType using A, B, C and D objects
        UpperBoundedWildcardType<A> genAObj = new UpperBoundedWildcardType<>(a);
        genAObj.showObjectType(genAObj);

        UpperBoundedWildcardType<B> genBObj = new UpperBoundedWildcardType<>(b);
        genBObj.showObjectType(genBObj);
 
        UpperBoundedWildcardType<C> genCObj = new UpperBoundedWildcardType<>(c);
        genCObj.showObjectType(genCObj);
 
        UpperBoundedWildcardType<D> genDObj = new UpperBoundedWildcardType<>(d);
        genDObj.showObjectType(genDObj);
    }
}

Running the TestUpperBoundedWildcardType class produces the following output:

Run test upper bounded wilcard type class
Screenshot 2. Running the TestUpperBoundedWildcardType class.

Well nothing new here, all the classes run as expected. Now we want to change the UpperBoundedWildcardType class so that only objects of type A or sublasses thereof can use the showObjectType(UpperBoundedWildcardType<T> obj) method and for this we need an upper bounded wildcard type.

Change the signature to showObjectType(UpperBoundedWildcardType<? extends A> obj) as shown below and rebuild the UpperBoundedWildcardType class.


package com.server2client;

/*
  Simple generic class that accepts any object
*/
public class UpperBoundedWildcardType<T> {

    // Generic object declaration
    private final T genericObj;

    // Pass reference to object of type T to our constructor
    public UpperBoundedWildcardType(T genericObj) {
        this.genericObj = genericObj;
    }

    // Output object type of UpperBoundedWildcardType to console 
    public void showObjectType(UpperBoundedWildcardType<? extends A> obj) { // Changed to bounded wild card type
        System.out.println("Object type of UpperBoundedWildcardType is " + genericObj.getClass().getName());
    }
}

Rebuilding the TestUpperBoundedWildcardType class after the amendments produces the following output:

Rebuild test bounded wilcard type class
Screenshot 3. Rebuilding the TestUpperBoundedWildcardType class after the amendments.

As you can see from the screenshot above the compiler won't allow us to call the showObjectType(UpperBoundedWildcardType<? extends A> obj) method with an object of class D because the method now has an upper bounded wildcard type that only allows the A class and its subclasses.

Remove the creation and call for the genDObj in the TestUpperBoundedWildcardType class for the class D type as shown below and rebuild the TestUpperBoundedWildcardType class.


package com.server2client;

/*
  Test our UpperBoundedWildcardType class that accepts any object
*/
public class TestUpperBoundedWildcardType {

    public static void main(String[] args) { 

        // Create some objects
        A a = new A(); 
        B b = new B(); 
        C c = new C(); 
    
        // Test the UpperBoundedWildcardType using A, B, and C objects
        UpperBoundedWildcardType<A> genAObj = new UpperBoundedWildcardType<>(a);
        genAObj.showObjectType(genAObj);

        UpperBoundedWildcardType<B> genBObj = new UpperBoundedWildcardType<>(b);
        genBObj.showObjectType(genBObj);
 
        UpperBoundedWildcardType<C> genCObj = new UpperBoundedWildcardType<>(c);
        genCObj.showObjectType(genCObj);
    }
}

Rerunning the TestUpperBoundedWildcardType class after the amendments produces the following output:

Rerun test upper bounded wilcard type class
Screenshot 4. Rerunning the TestUpperBoundedWildcardType class after the amendments.

Ok, now we have seen how to use an upper bounded wildcard type lets look at an example of using the lower bounded wildcard type.

Lower Bounded Wildcard Type Top

Related Quiz

Generics Quiz 7 - Upper Bounded Wildcard Type Quiz

Lesson 7 Complete

In this lesson we looked at the generic upper bounded wild card type and how to use it.

What's Next?

In the next lesson we look at the generic lower bounded wild card type and how to use it.