Java generic method constraints - exclude type from constraint to prevent erasure problems?

这一生的挚爱 提交于 2020-02-02 10:10:11

问题


I am trying to overload a method based on type constraints. The code looks something like this:

protected  static <T extends ComponentTemplate> void addComponent(List<ComponentTemplate> factors, T component)
{
    ...
}

    protected  static <T extends ComponentTemplate
                       & ConditionalComponent> void addComponent(List<ComponentTemplate> factors, T conditionalComponent)
{
    ....
}

ComponentTemplate is an abstract class, and ConditionalComponent is an interface. These two methods can add a component to a list of components. In the case that the component implements ConditionalComponent, there will be additional methods that should be used to determine if the specific component should be added. A completely different approach is used when the object does not implement ConditionalComponent.

The problem is that these methods have the same erasure (according to RAD, which of course refuses to compile this). Is there a way to define the first method such that it excludes any objects that extends both ComponentTemplate AND ConditionalComponent? I imagined something like this:

    protected  static <T extends ComponentTemplate
                       & !ConditionalComponent> void addComponent(List<ComponentTemplate> factors, T component)
{
    ...
}

But of course, that doesn't work (it's not valid syntax). Is what I'm trying to do even possible, or is there a work-around?


回答1:


This is not allowed. Why not?

When methods are called in Java, the method with the most specific type signiture is used.

In the example:

interface A {...}
interface B {...}
class X extends A, B {...}

void f(X);
void f(A);
void f(B);

X x = ...
f(x); // calls f(X)
f((A)x); // calls f(A)
f((B)x); // calls f(B)

We all know how to cast to call the correct method we want.

But in the example

<T extends X> void g(T);     //G1
<T extends A & B> void g(T); //G2

g(x); // calls G1

We can call G1, but there is no way to call G2 without redirection. We cannot downcast to A & B, only to either A or B.

The A & B does not seem well intgrated into the type system (most people won't even know of it), therefore Java does not see A as being a different type from A & B when choosing which version of a method to dispatch to.


Futher examples of madness:

interface A
interface B extends A

<T extends A & B> void f(T)
<T extends B> void f(T)

This will compile, but you can't call either of them

B b = new B(){...}
f(B); // method reference is ambiguious.


来源:https://stackoverflow.com/questions/23392586/java-generic-method-constraints-exclude-type-from-constraint-to-prevent-erasur

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!