简体   繁体   中英

Java - Defining a member that extends class A and implements interface B

I have a variable that must meet two conditions, and I want to set them in the definition

I know that I can define either condition with an individual variable, like in any of these examples

private Class<? extends A> variable; //or
private A variable; //or
private Class<? extends B> variable; //or
private B variable;

But is there a way to have the variable meet both conditions?

I was hoping for something like this

private Class<? extends A implements B> variable;

But I can't find any way to do this without typecasting when I need to call it or storing multiple copies of it

You can declare type parameters that have multiple bounds, such as:

public static <T extends A & B> void test(Class<T> clazz)

But you cannot declare a variable that has multiple bounds:

private Class<? extends A & B> variable;  // doesn't work

You can create an abstract class C that extends A and implements B , so that only one bound is required.

abstract class C extends A implements B {}

Then:

private Class<? extends C> variable;

While Java does not directly support intersection types like A&B , such types do appear in type parameter bounds and capture conversions. We can express A&B with a layer of abstraction.

public class ValueAB<T extends A&B>
{
    public final T v;

    // constructor ...
}

public class ClassAB<T extends A&B>
{
    public final Class<T> clazz;

    // constructor ...
}

Instead of A&B, Class<? extends A&B> A&B, Class<? extends A&B> , we use wrappers ValueAB, ClassAB

    ClassAB<?> clazz = new ClassAB<>(Foo.class);   

    ValueAB<?> value = new ValueAB<>(clazz.c.newInstance());

    value.v.methodOfA();
    value.v.methodOfB();

This solution would require a wrapper for each combination of As and Bs.


Another solution is to use only A as type parameter bound; B will be supplied by wildcard bound. This is probably better if you need to express multiple A&B1, A&B2, ... types at use site.

public class ValueA<T extends A>
{
    public final T v;
    ...
}


public class ClassA<T extends A>
{
    public final Class<T> c;
    ...
}

---

    ClassA<? extends B> clazz = new ClassA<>(Foo.class);

    ValueA<? extends B> value = new ValueA<>(clazz.c.newInstance());

If it's confusing how wildcard works in these cases, see my article on wildcard


A 3rd solution is free of A or B at declaration site of wrappers; the use site provides A and B.

public class Value<T extends S, S>
{
    public final T v;
    ...
}


public class Clazz<T extends S, S>
{
    public final Class<T> c;
    ...
}

---

    Clazz<? extends A, B> clazz = new Clazz<>(Foo.class);

    Value<? extends A, B> value = new Value<>(clazz.c.newInstance());

This is however probably too confusing.

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