General factory of common containers

I have a generic Factory<T> abstract class with the createBoxedInstance() method that returns T instances created by createInstance() implementations wrapped in a generic Box<T> container.

 abstract class Factory<T> { abstract T createInstance(); public final Box<T> createBoxedInstance() { return new Box<T>(createInstance()); } public final class Box<T> { public final T content; public Box(T content) { this.content = content; } } } 

In some cases, I need a container like Box<S> , where S is the ancestor of T Is it possible to make createBoxedInstance() itself generic so that it returns Box<S> instances where the caller called S ? Unfortunately, defining a function as follows does not work, since a type parameter cannot be declared using the super keyword, only used.

 public final <S super T> Box<S> createBoxedInstance() { return new Box<S>(createInstance()); } 

The only alternative that I see is to create all the places that need an instance of Box<S> accept Box<? extends S> Box<? extends S> , which allows the container content member to be assigned S

Is there a way around this without repeatedly boxing T instances into Box<S> containers? (I know that I could just drop Box<T> to Box<S> , but I would be very, very guilty.)

+4
source share
3 answers

Try rewriting another code to not use Box<S> , but use Box<? extends S> Instead Box<? extends S> , so it will also accept Box<T> . This way you clearly indicate that Box can also contain subclasses of S

The following should also work if you make your box static :

 public static <S, T extends S> Box<S> createBoxedInstance(Factory<T> factory) { return new Box<S>(factory.createInstance()); } 

However, for S may not be possible to infer the type in which you need to:

 public static <S, T extends S> Box<S> createBoxedInstance(Factory<T> factory, S dummy) { return new Box<S>(factory.createInstance()); } 

Another variation that is very famous:

 public static <S, T extends S> Box<? extends S> createBoxedInstance(Test<T> factory, S dummy) { return factory.createBoxedInstance(); // Actually a Box<T> } 
+2
source

To some extent, you can achieve what you want:

 public final <S extends Box<? super T>> S createBoxedInstance() { // sadly we can't capture the wildcard in the bound of S // this means we have to cast, but at least it local.. // *should* this cast ever break due to reification, we // can fix it here and be good to go @SuppressWarnings("unchecked") S box = (S) new Box<T>(createInstance()); return box; } Factory<Integer> factory = getFactory(); Box<Number> box1 = factory.createBoxedInstance(); Box<Object> box2 = factory.createBoxedInstance(); 

I think your own Box<? extends S> Box<? extends S> -Alternative is the right approach. However, if this causes client code to be flooded with wildcards, this may be preferable.

0
source

The reason you cannot do this (or use weird transforms) is as follows: Imagine that there was also a setter in the Box field, and not in the final. Also, suppose that type S is a super-type of both R and T. The following code will be valid without casting.

 Box<T> boxT = new Box<T>(objectT); Box<S> boxS = boxT; S objectR = new R(); boxS.set(objectR); 

This code will be valid without warning, except that the installer will fail at runtime with an unexpected exception (unexpected in the sense that it is not obvious that a casting exception can be thrown) because you cannot assign something with type R to type T.

You can read more at http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Topic3 (but you have aspirin, you will get a headache)

Like many people, probably using code in other code is the best option.

0
source

Source: https://habr.com/ru/post/1382941/


All Articles