A Brief introduction to Java generics allows declared methods to return subtypes

  • 2020-06-12 09:15:12
  • OfStack

A typical use case for generics is collections. Considering that most collections are homogenous (same type 1), you can avoid the hassle of casting by declaring parameter types. This article will discuss a problem I encountered while reading the Spring Security source code with respect to generic recursive patterns.

Declared methods return subtypes

There is an ProviderManagerBuilder interface in the Spring Security source code, declared as follows


public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> extends SecurityBuilder<AuthenticationManager> {
  B authenticationProvider(AuthenticationProvider authenticationProvider);
}

Its implementation class, AuthenticationManagerBuilder


public class AuthenticationManagerBuilder extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder> implements ProviderManagerBuilder<AuthenticationManagerBuilder> {

  //...

  public AuthenticationManagerBuilder authenticationProvider(
    AuthenticationProvider authenticationProvider) {
    this.authenticationProviders.add(authenticationProvider);
    return this;
  }

  //...

}

There's a lot of interference up here, so let's simplify by 1

The interface A is defined as follows


public interface A<T extends A<T>> {

  T add();

} 

Note: the A interface has only 1 add method, which returns the generic T. T's statement was somewhat lenient < T extends A < T > > .

The implementation class B for the A interface


public class B implements A<B> {

  @Override
  public B add() {
    return null;
  }

} 

Note that the add method in the class B here returns the type B. In other words, methods declared in interface A are not aware of the subtype B. Through inheritance and generics, it is possible to put adaptive subtypes with return values dynamically, all thanks to this < T extends A < T > >

Generic recursive schema (Recurring Generic Pattern)


public interface A

public abstract class Enum<E extends Enum<E>>
  implements Comparable<E>, Serializable {
  //...
}

All java enumeration types implicitly inherit java.lang.Enum, do not allow enumeration types to be declared by real inheritance, and even integration java.lang.Enum is not allowed by the compiler.

Suppose you have an enumeration class StatusCode, whose equivalent is declared as follows

public class StatusCode extends Enum < StatusCode >

Now let's verify 1 that the generic constraint,

1. Because Enum < StatusCode > So E=StatusCode;

2. According to < E extend Enum < E > > And E=StatusCode, < StatusCode extend Enum < StatusCode > > ;

3. Due to public class StatusCode extends Enum < StatusCode > The conclusion of step 2 is clearly true.

Why is Enum's claim so convoluted? Direct Enum?

Because Enum < E > Implements the Comparable < E > Interface, which has 1 compareTo method

public int compareTo(E o) {}

< E extend Enum > The call object and parameter types for 'compareTo' are strictly 1 bound, and no comparison between subclasses and superclasses or siblings occurs.

Generic recursive patterns and inheritance

The generic recursive pattern interface A < T extend A < T > > Used to constrain the parameter type T to be a subclass of type A.

Consider inheritance and implementation of B implements A < B > , the parameter type and entity type are 1. Thus, where the method signature in class A refers to the parameter type T, the implementation class will be the implementation class itself, which makes the type system more rigorous.


Related articles: