简体   繁体   中英

Java abstract generic method with wild card implemented with concrete type

Is it possible in java to define an abstract method with wildcard but in the implementation use a concrete type

eg:

Define the abstract method in an abstract class like this

public abstract class AbstractAuthorizer {
    abstract protected <T extends User> void authorize( T user );
}

Implement the abstract method like this, where CorporateUser extends User :

public class CorporateAuthorizer extends AbstractAuthorizer {

    @Override
    protected <CorporateUser> void authorize(CorporateUser user){
    }
}

No you can't directly do what you're asking for. However, you can get the same effect.

When you make something generic, you're making a promise to the user: this will work for any type satisfying the generic bounds . So by picking a specific type in the subclass, you're breaking that rule. However, if you define the superclass correctly then you can get the behavior you want while satisfying the type checker as well. Instead of making the function generic, make the class generic, and then when you subclass it you get to choose which type it works on.

public abstract class AbstractAuthorizer<T extends User> {
    abstract protected void authorize( T user );
}

public class CorporateAuthorizer extends AbstractAuthorizer<CorporateUser> {
    @Override
    protected void authorize(CorporateUser user) {}
}

The abstract class is declaring a method which will authorize any <T extends User> . Your extension is not meeting this contract.

Some options:

  1. Generify the abstract class.

     abstract class AbstractAuthorizer<T extends User> { protected abstract void authorize(T user); } class CorporateAuthorizer extends AbstractAuthorizer<CorporateUser> { protected void authorize(final CorporateUser user) { // Do authorization. } } 
  2. Have the extension perform the necessary checks. Something along the lines of (with AbstractAuthorizer defined as you have):

     class CorporateAuthorizer extends AbstractAuthorizer { protected <T extends User> void authorize(final T user) { if (!(user instanceof CorporateUser)) { throw new UnsupportedOperationException("CorporateAuthorizer can only authorize 'CorporateUser' users"); } // Do authorization. } } 

If you're going with the latter, I would strongly suggest an additional abstract boolean supports(User user); which does the above instanceof check so that it can be used as:

boolean checkAuth(final User user) {
    boolean authorized = false;
    for (final AbstractAuthorizer authorizer : authorizers) {
        if (authorizer.supports(user)) {
            authorizer.authorize(user);
            authorised = true;
            // break; if only a single authorizer's check is required.
        }
    }
    return authorised;
}

I'll also note that the approach with <T extends User> in the latter has no benefit over simply using User , unless you're going to return the User if authorized. Ie,

abstract class AbstractAuthorizer {
    abstract boolean supports(User user);

    abstract <T extends User> T authorize(T user);
}

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