Generic parent cannot be returned as a child

This question might be like passing a Parent object to a Child object in C # , but it is about C # and I have a question about Java.

I'm also going to create an ancestor. The generator builder only has to create parts of the abstract object, and all children manage the individual implementations of the abstract class.

abstract class GenericBuilder<B extends GenericBuilder>
{
     //lots of build methods
     public B lastBuildingMethodInTheChain(Object someValue)
     {
          //assignment
          return this;//<-- is not allowed!
     }
}

      

But when I put in the casting: return (B) this;

it's fine. The cast is what I want to prevent, but it also restricts children from using their special methods. The latter makes sense because the Generic type is only known at runtime, but I don't know how to write it to make it work at compile time.

Thank!

+1


source to share


3 answers


Correct way to declare GenericBuilder

with f-bound type :

abstract class GenericBuilder<B extends GenericBuilder<B>> {

    public B lastBuildingMethodInTheChain(Object someValue) {
        // assignment
        return (B) this;
    }
}

      

You cannot avoid casting, because the compiler needs to know that this generic constructor is in fact the specific creator of the type parameter.

You can extend the generic constructor like this:



public class ConcreteBuilder1 extends GenericBuilder<ConcreteBuilder1> {

}

      

It is reasonable to assume that the throw is safe. The only way to fail the command is to declare ie:

public class ConcreteBuilder2 extends GenericBuilder<ConcreteBuilder3> {

}

      

But why would you do that?

+1


source


In the example of the various methods for creating a guava, you can see an example of a typical gradual taper pattern (the name I probably just drew). After all, the cast is necessary, but you can hide it well enough:

@SuppressWarnings("unchecked")
private <B1 extends B> GenericBuilder<B1> me() {
  return (GenericBuilder<B1>) this;
}

      

used like this:

public B lastBuildingMethodInTheChain(Object someValue) {
  B self = me();
  self.assignWhatever = someValue;
  return me;
}

      



(I'm not 100% sure that this will work exactly the same - because of the extra oddity when an object is parameterized as a subclass of itself.)

Below are some similar examples:

Note the use of a method getThis()

that avoids broadcasting.

+2


source


This makes no sense. it is GenericBuilder and B is extending GenericBuilder since you are going to revert that (since GenericBuilder does not extend itself (tautologically)

+1


source







All Articles