Java generators in hiding type parameter

Suppose I have such an interface

public interface Foo<Ret, Arg> { public Ret doSomething(Arg arg); } 

And a specific implementation class that only has package visibility.

 class FooImpl<Ret, Arg1, Arg2> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Arg2> { // This class also implements something else making use of Arg2, so you cannot safely remove it // But nothing relating to Arg2 is needed to create a FooImpl } 

(An example of how this can happen is the implementation of Foo and Bar in FooImpl forwards methods declared by two interfaces to one varargs method)

Now suppose that there is a static method somewhere in the same package that returns FooImpl as Foo . You might think that you can use return new FooImpl<Ret, Arg1, ?>(...) when you really can't (you should use a specific dummy type like Arg2 , for example, return new FooImpl<Ret, Arg1, Object>(...) , say).

Any idea why this is so, especially since the Foo interface and package visibility effectively hide FooImpl from using the static method? This is due to the fact that to some extent you can use reflection to get to the Bar parts of FooImpl , where you need a specific type?

+4
source share
2 answers

The Java compiler tries not to be smart. There are many situations where it is obvious that he does not need any information to get the correct code, but he still complains. When Java was invented, the world saw C with a sloppy attitude to try to compile everything, no matter how dangerous or stupid. The goal of javac was to make sure people can't easily shoot in the foot .

Therefore, he suggests that there is reason that you mention Arg2 - if it was not necessary for something, you probably would not have put it into the code.

Solutions:

  • Assign a type when implementing Bar : class FooImpl<Ret, Arg1> implements Foo<Ret, Arg>, Bar<Ret, Arg1, Object>
  • Create BetterFooImpl<Ret, Arg1> extends FooImpl<Ret, Arg1, Object> . This hides the third type argument from API users.
  • Try to get rid of the third parameter Bar
  • Use generics carefully. This may be surprising, but there are situations where generics simply do not work. This is usually due to the subtle implementation details that cause the explosion of @SuppressWarning annotations. When this happens, I ask about SO, and when I cannot find a solution that I can understand, I delete the generics. It is more important to write supported code than to find smart ways in the maze of generics.
+1
source

I think this has nothing to do with your particular design.

You simply cannot create types with wild cards.

This will not work:

 return new ArrayList<?>(); 

And if that happened, do something else besides

 return new ArrayList<Object>(); 

You need a specific class, but this does not mean that you need to show it in your factory method signature:

 static <A,B> Foo<A,B> makeFoo(){ return new FooImpl<A,B, SomeTypeThatNoOneNeedsToSee>(); } 
+4
source

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


All Articles