[Java] Introducing the Generics Boundary Wildcard Type

Boundary wildcard type role

Java generic types cannot convert List <Integer> types to List <Number> types.

Different types


//If the OK type parameters are the same
List<Integer> foo = new ArrayList<Integer>();

// NG List<Integer>Is a List<Number>Cannot be converted to
List<Number> bar = foo;

//Similarly, conversion is not possible even with NG initialization
List<Number> foo = new ArrayList<Integer>();

Therefore, by using ** boundary wildcard type **, you can declare ** type parameters with some width **. However, there are two types of boundary wildcard types. This is because when the type boundaries are set, the problem that the processing system cannot set the type occurs in each situation. Let's look at the problem one by one.

The following Fruit class is used for explanation.

Fruitクラス.png

Wildcard type with upper limit

Generic<? extends T>

If you specify a type parameter as above, the type parameter is ** capped wildcard type **. The ? extends T </ kbd> type means ** T or a type that represents all of its subclasses **.

?_extends_fruit.png

Considering using the List <? Extends Fruit> type, it is possible to convert from ** Fruit class or List type ** that specifies its subclass.

List that can be converted


List<? extends Fruit> basket = new ArrayList<Fruit>(); // 1
List<? extends Fruit> basket = new ArrayList<Melon>(); // 2
List<? extends Fruit> basket = new ArrayList<Lemon>(); // 3

Next, consider retrieving an element from the List <? Extends Fruit> basket variable, Please be aware that the basket variable can be retrieved as a Fruit class regardless of whether it is 1, 2, or 3.

Read

Conversion from "boundary wildcard type with upper limit" to "T class type"

Consider retrieving an element from a List <? Extends Fruit> basket variable. In the case of a wildcard type with an upper limit, it is ** at least a type that represents the T class and its subclasses **, so it is possible to specify the upper limit T when retrieving an element from the List.

Convert capped wildcard type to T type


List<? extends Fruit> fruits = ...

//no problem
Fruit fruit = fruits.get(i);

This is a conversion from ? Extends T type to T type.

Conversion from "Limited Boundary Wildcard Type" to "T Subclass Type"

Next, when you get the element from the basket variable, consider whether you can specify its subclass. The List <? Extends Fruit> type can be converted from at least the following three List types.

  1. ArrayList<Fruit>
  2. ArrayList<Melon>
  3. ArrayList<Lemon>

Therefore, when getting an element, it is not possible to specify a subclass that derives from several series.

Uppered wildcard types cannot be converted to subclass types


List<? extends Fruit> basket = ...

//NG compilation error Cannot convert to Melon type
Melon fruit = basket.get(i);

Above, if the ? Extends Fruit type can be converted to a subclass, the following contradictions will occur.

Convert capped wildcard type to T subclass type 1


//Make a melon list
List<Melon> melonList = new ArrayList<Melon>()
melonList.add(new Melon());

// List<Melon>List type melonList<? extends Fruit>Convert to type
List<? extends Fruit> basket = melonList;

//If it can be converted to a subclass, it will be possible to receive it as Lemon.
Lemon fruit = basket.get(i);

Therefore, conversion to a subclass is not allowed. Therefore, it is not possible to convert from a ? Extends T type to aT subclasstype.

writing

Next, consider adding an element to the List <? Extends Fruit> fruits variable. Since you can convert from ? Extends Fruit type to Fruit type, it seems that you can add a Fruit object to the following fruits variable.

Write to capped wildcard type


List<? extends Fruit> fruits = new ArrayList<Fruit>();

//Seems possible at first glance
fruits.add(new Fruit());

However, if the above is allowed, the following contradictions will occur.

Writing to a capped wildcard type is inconsistent


//The reality of fruits is a melon list
List<? extends Fruit> fruits = new ArrayList<Melon>();
//The Lemon class is a subclass of the Fruit class
Fruit fruit = new Lemon();

//Lemons can be added to the melon list
fruits.add(fruit);

Therefore, it is not possible to convert from the concrete type T type orT subclasstype to? Extends T type. This means that if you declare a List type with a capped wildcard, you cannot add elements. That's where another boundary wildcard type comes in.

Wildcard type with lower limit

Generic<? super T>

If you specify a type parameter as above, it is ** a wildcard type with a lower bound **. The ? super T </ kbd> type means ** T or a type that represents all of its superclasses **.

?_super_melon.png

You can convert to ** List \ <? Super Melon > ** type from ** Fruit class or List type ** whose type parameter is its superclass.

List that can be converted


List<? super Melon> baskets = new ArrayList<Melon>(); // 1
List<? super Melon> baskets = new ArrayList<Fruit>(); // 2
List<? super Melon> baskets = new ArrayList<Food>(); // 3
List<? super Melon> baskets = new ArrayList<Object>(); // 4

This time around, I'll think about adding elements to the basket variable first, Please be aware that Melon class can be added to the basket variable in 1 to 4 when it is 1, 2, 3 or 4.

writing

Conversion to lower bound wildcard type

To add an element to a List <? Super Melon> basket variable, the wildcard type with a lower bound is ** a type that represents at least a T class or higher superclass **, so the element is added to the List type. When adding, you should be able to specify its lower bound, T.

Check that you can add one by one by referring to the example.

When List <? Super Melon> fruits = new ArrayList <Object> ()

Add to Object list


// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());

When List <? Super Melon> fruits = new ArrayList <Food> ()

Add to Food list


// OK
fruits.add(new Melon())
// OK
fruits.add(new WaterMelon());

When List <? Super Melon> fruits = new ArrayList <Melon> ()

Add to Melon list


// OK
fruits.add(new Melon());
// OK
fruits.add(new WaterMelon());

That is, it is possible to convert from a T or T subclass type to a ? Super T type.

Read

The ? super Melon </ kbd> type is a "type that represents the Melon class and all of its superclasses". Also, all Java classes inherit from the ** Object ** type. Therefore, conversion from ? Super T type to ʻObject` type is possible.

Conversion from wildcard type with lower limit to Object type


Object object = basket.get(i)

Summary

Appendix

What it means to write a value with a boundary wildcard type

You may have heard that when you specify a bounding wildcard type with an upper bound, the List cannot be written.

This simply means that you cannot:

** Cannot convert concrete type to capped wildcard type **

If you declare a generics type object with a capped wildcard, the above conversion will occur when you call a function with that type parameter.

Consider the Stack \ <T > class below.

Stack class


class Stack<T> {
    void push(T e) {}
}

Declare the Stack \ <T > class with a capped wildcard type.

Stack<? extends Fruit> basket = new Stack<Fruit>();

At this time, the type parameter T of the basket variable is of type ? Extends Fruit. So the push method is equivalent to:

When the Stack type parameter is a capped wildcard


void push(`? extends Fruit` e) {}

Therefore, calling this push method results in a conversion from a Fruit to a? Extends Fruit type. And this conversion is NG.

//NG Fruit type`? extends Fruit`Cannot be converted to type
basket.push(new Fruit()); 

Recommended Posts

[Java] Introducing the Generics Boundary Wildcard Type
[Java] Generics
Java Generics Summary
Introducing the library
[JAVA] Stream type
[Java] Generics sample
The intersection type introduced in Java 10 is amazing (?)
Java Generics (Notes)
[Java] Enumeration type
Java Optional type
[Java] Be careful of the key type of Map
Java double type
About the meaning of type variables, E, T, etc. used in generics used in Java
Organized memo in the head (Java --Data type)
Java getClass () is incompatible with generics (or type variables)
[Java] Data type ①-Basic type
Frequently used Java generics
null specifies the type
[Java, Kotlin] Type Variance
Java class type field
Type determination in Java
Java study # 1 (typical type)
[Java] About enum type
[Java] Date type conversion
Find the address class and address type from the IP address with Java
[Java] To know the type information of type parameters at runtime