The related parameter types in the general method do not work while the equivalent common interface is working, why?

Let's start with 3 interfaces. What they do is not important. Just note that Car is parameterized (), while Foo and Bar are not.

interface Foo {void testFoo();} interface Bar {void testBar();} interface Car<A> {A testCar();} 

I want to β€œcompose” these interfaces, and this works fine if I explicitly create such composites:

 interface FooBar extends Foo,Bar {} interface FooCar<A> extends Foo,Car<A> {} 

However, I would prefer to implicitly combine interfaces through declarations of a limited type of various methods. For instance:

 public <T extends Foo & Bar> T implicitFooBar() {return null;} public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;} 

WORKS: The implictFooBar () method returns a type T that implements both the Foo and Bar interfaces (composite, if you like). The call to this method compiles, and I can avoid explicitly declaring the FooBar interface:

 // implicit composition of Foo and Bar, GOOD FooBar implicitFooBar = implicitFooBar(); implicitFooBar.testFoo(); implicitFooBar.testBar(); 

FAILs: However, the implicitFooCar () call cannot be compiled. Error message: "The implicitFooCar () method in the GenericsTest type is not applicable for the arguments ()" (I wrapped my test code in the GenericsTest class.)

 // implicit composition of Foo and Car<X>, FAIL! //Compiler says "The method implicitFooCar() in the type GenericsTest is not applicable for the arguments ()" FooCar<Number> implicitFooCar = implicitFooCar(); //compile error on method call implicitFooCar.testFoo(); Number n2 = implicitFooCar.testCar(); 

A compiler error indicates when a type declaration is compound and parameterized. For example, both of these compilations can be called just fine:

 public <X> Car<X> justCar() {return null;} public <X, T extends Car<X>> T implicitCar() {return null;} 

Question...

I suspect this is due to the erasure of styles, but I would like to understand the details of what is happening here. I read Oracle Generics tutorials, but I don’t see which combination of rules the implicitFooCar () method violates, while implicitFooBar () and implicitCar () are fine. I'm looking for an explanation of the academic style, not just a job.

Bonus

Interestingly, the next option to invoke the implicitFooCar () method works (without compiler errors). This indicates why the other version is not working, but I have not connected these points yet.

 //variant... GOOD... but why? implicitFooCar = this.<Number,FooCar<Number>>implicitFooCar(); 

Test code (integer)

If you want to play with the code, here it is like one class.

 public class GenericsTest { public static interface Foo {void testFoo();} public static interface Bar {void testBar();} public static interface Car<A> {A testCar();} public static interface FooBar extends Foo,Bar {} public static interface FooCar<A> extends Foo,Car<A> {} public <X> Car<X> justCar() {return null;} public FooBar explicitFooBar() {return null;} public <T extends Foo & Bar> T implicitFooBar() {return null;} public <X> FooCar<X> explicitFooCar() {return null;} public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;} public <X, T extends Car<X>> T implicitCar() {return null;} public void test() { justCar().testCar(); // explicit composition of Foo and Bar, GOOD FooBar explicitFooBar = explicitFooBar(); explicitFooBar.testFoo(); explicitFooBar.testBar(); // explicit composition of Foo and Car<X>, GOOD FooCar<Number> explicitFooCar = explicitFooCar(); explicitFooCar.testFoo(); Number n1 = explicitFooCar.testCar(); // implicit composition of Foo and Bar, GOOD FooBar implicitFooBar = implicitFooBar(); implicitFooBar.testFoo(); implicitFooBar.testBar(); // implicit composition of Foo and Car<X>, FAIL! //Compiler says "The method implicitFooCar() in the type GenericsTest is not applicable for the arguments ()" FooCar<Number> implicitFooCar = implicitFooCar(); //compile error on method call implicitFooCar.testFoo(); Number n2 = implicitFooCar.testCar(); //variant... GOOD... but why? implicitFooCar = this.<Number,FooCar<Number>>implicitFooCar(); // implicit (no composition) Car<X>, GOOD Car<Number> implicitCar = implicitCar(); Number n3 = implicitCar.testCar(); } } 

UPDATE

This is a compilation with javac version 1.8.0_60 (and _45 for comments), but the Eclipse (version 4.4.2.M20150204-1700) built into the ECJ compiler reports the error mentioned above. I have added an eclipse tag to this question as this may be an EJC problem.

+5
source share
1 answer

First, to directly answer my question ... You can declare a method with an associated parameterized type that combines two interfaces, one of which is parameterized itself.

The implicitFooCar () method from my example failed due to an error in the Eclipse ECJ compiler, which was used in Luna version 4.4 of Eclipse. The same code compiled using the javac compiler (v 1.8.0_60) in the next version of Eclipse, Mars (4.5).

Secondly, my desire to avoid explicit statements about what I considered to be temporary or intermediate composite interfaces was short-sighted. Louis Wasserman pointed out that the method at some point should return an object that matches this composite specification, and therefore, I will need an explicit version at this point.

+2
source

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


All Articles