Upper Bounded Wildcard TypeJ8 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.
Term | Examples | Notes | Lesson |
---|---|---|---|
Upper Bounded Wildcard Type | List<? extends Number> | Create a superclass boundary which all unknown types must be, or subtypes thereof. | This lesson |
Lower Bounded Wildcard Type | List<? 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 info.java8;
public class A {
{
System.out.println("A Object initializer");
}
}
package info.java8;
public class B extends A {
{
System.out.println("B Object initializer");
}
}
package info.java8;
public class C extends B {
{
System.out.println("C Object initializer");
}
}
package info.java8;
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 B
class and subclasses of it; first we will let
the method work with any type:
package info.java8;
/*
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:
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 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:
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 subclasses 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 info.java8;
/*
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 upper 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:
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 info.java8;
/*
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:
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.