简体   繁体   中英

Understanding generics syntax in java - generic types implementing multiple interfaces as parameters

I have some interfaces (and for completeness two dummy classes, so you may copy the code into your ide)

public interface ItfA
{
  String getA();
}

public interface ItfB
{
  String getB();
}

public class MyClassAdapter
{
    public Object getValue(Object bean)
    {
        return null; // override to do something useful
    }
}

public class MyClass
{
    public MyClass(MyClassAdapter mca)
    {
        // do something useful with it
    }
}

And I have some functions using these as parameters (looks a bit weird, but that's how I have to use them (I can't change the MyClassAdapter )) ...

public <T extends ItfA> MyClass getMyClass(final Class<T> itf)
{
    return new MyClass(new MyClassAdapter()
        {
            @Override
            public Object getValue(Object bean)
            {
                return itf.cast(bean).getA();
            }
        }
    );
}

So I can call this getMyClass only with classes implementing interface ItfA - otherwise the compiler will complain.

Alternatively I can rewrite this method without the named generic type T as ...

public MyClass getMyClass2(final Class<? extends ItfA> itf)
{
    return new MyClass(new MyClassAdapter()
        {
            @Override
            public Object getValue(Object bean)
            {
                return itf.cast(bean).getA();
            }
        }
    );
}

In some cases I need classes as parameters that implement more than one interface - this will work:

public <T extends ItfA & ItfB> MyClass getMyOtherClass(final Class<T> itf)
{
    return new MyClass(new MyClassAdapter()
        {
            @Override
            public Object getValue(Object bean)
            {
                return itf.cast(bean).getA() + itf.cast(bean).getB();
            }
        }
    );
}

but this one doesn't work

public MyClass getMyOtherClass2(final Class<? extends ItfA & ItfB> itf)
{
    return new MyClass(new MyClassAdapter()
        {
            @Override
            public Object getValue(Object bean)
            {
                return itf.cast(bean).getA() + itf.cast(bean).getB();
            }
        }
    );
}

I don't get the difference between these two kinds of generic parameters ( <T extends ItfA> before the method name and using Class<T> in the parameters opposed to using Class<? extends ItfA> in the parameters) - why do both types work with one interface, and why does one work with two interfaces, but the other one doesn't.

Any hints? To me, the second variant is a bit more readable, so I'd prefer that, but I don't get it to work with multiple interfaces ...

Unlike TypeParameter , TypeArgument can't have several bounds, so <? extends ItfA & ItfB> <? extends ItfA & ItfB> is not valid.

Here's my guess on why it is so.

I think the reason is that TypeArgument needs to be specific to be useful. For instance in case of Class<T> the method cast returns T , you should be able to declare a variable of that type and assign the result to it.

TypeArgument can be:

  1. ClassType
  2. InterfaceType
  3. TypeVariable
  4. ArrayType
  5. Wildcard

Cases 1-4 are not problematic, there you always have some specific type or type variable.

In case of the Wildcard we have WildcardBounds for instance <? extends IntfA> <? extends IntfA> .

If you allow just one upper bound, then you have something specific for T . In case of Class<? extends IntfA> Class<? extends IntfA> you can assume that cast returns InfA .

If you allow more that one upper bound <? extends ItfA & ItfB> <? extends ItfA & ItfB> then the question is, what could you use for T then? Since you in general case you don't have any specific type for T , the best you can do is Object which is not very useful.

I think this is the reason language authors did not allo multiple upper bounds for wildcard type arguments.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM