Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declare a Member variable of both a class and interface in Java

I have a class with a constructor that accepts one argument that must be of the class Context (or any subclass) and implement the interface Alertable. I will use this argument to set a member variable that will then be used throughout the class as either an instance of Context or an instance of Alertable.

public <T extends Context & Alertable> ApiGateway(T context)
{
     // Constructor code here
}

How can I declare a member variable mAlertableContext such that it is also both of class Context and implements interface Alertable?

I've tried sticking the generic definition in various places in the code, but they keep coming up as syntax errors. Ideally, I'd like to have a member variable like <T> mAlertableContext or something similar, where I can treat mAlertableContext as either a Context or an Alertable.

One (admittedly very bad) workaround I've come up with is to declare two member variables, one of type Context and the other Alertable, and assign them both the same constructor argument and use them as which ever class/interface object I need them to be in the class ApiGateway.

private Context mContext;
private Alertable mAlertable;

public <T extends Context & Alertable> ApiGateway(T context)
{
    mContext = context;
    mAlertable = context;
}

I'm really hoping there is a better way to do this as it's obviously a duplication of data.

like image 396
The Unknown Dev Avatar asked Feb 23 '26 12:02

The Unknown Dev


1 Answers

I like the idea to use one "mAlertableContext" member variable from the perspective of ApiGateway. In any case, you are required to define how to deal with an object that is an Alertable and a Context. In creating an "mAlertableContext" variable, you are specifically required to create a definition of the combination of an Alertable and a Context object.

I think the best approach is to follow ajb's comment suggestion and create an AlertableContext class for the ApiGateway. Abstract the details of how you combine an Alertable and a Context away from the ApiGateway and put these details into the AlertableContext - on a need-to-know basis, the ApiGateway doesn't need to know how you've defined the combination of Alertable and Context. Leave that definition to the AlertableContext class.

It makes sense to have an Alertable variable and a Context variable in the AlertableContext class because the AlertableContext itself defines that its object may be one or the other, so the two variables of AlertableContext serve as a map between methods and their implementations. The Alertable and Context variables are references to the same object, so there are not two objects taking up memory space. They're just mapping definitions.

public class ApiGateway {

    private AlertableContext mAlertableContext;

    public <T extends Context & Alertable> ApiGateway(T context) {
        // Constructor code here
        mAlertableContext = new AlertableContext(context);
    }

    public void doAnApiCall() {

        // now the Context and Alertable members are available from mAlertableContext
        mAlertableContext.alert();
        mAlertableContext.doAContextThing();
    }
}

class AlertableContext extends Context implements Alertable {

    private Context context;
    private Alertable alertable;

    <T extends Context & Alertable> AlertableContext(T alertableContext) {
        this.context = alertableContext;
        this.alertable = alertableContext;
    }

    // override Context methods
    @Override
    public void doAContextThing() {
        context.doAContextThing();
    }

    // required from Alertable
    public void alert() {
        alertable.alert();
    }
}

If you don't like the separate variables, I know of one more option -- casting. You can avoid separate Alertable and Context objects and have an Object type object. Personally I think this is a bit more confusing, but it should work.

class AlertableContext extends Context implements Alertable {

    private Object alertableContext;

    <T extends Context & Alertable> AlertableContext(T alertableContext) {
        this.alertableContext = alertableContext;
    }

    // override Context methods
    @Override
    public void doAContextThing() {
        ((Context) alertableContext).doAContextThing();
    }

    // required from Alertable
    public void alert() {
        ((Alertable) alertableContext).alert();
    }
}
like image 178
Luke Avatar answered Feb 25 '26 01:02

Luke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!