Java Generics restrict to interface

后端 未结 3 2447
时光取名叫无心
时光取名叫无心 2021-02-20 05:44

I\'m not sure if this is possible or not, but what I want to accomplish is this:

public static  B makeB(A thing) {...}


        
相关标签:
3条回答
  • 2021-02-20 06:16

    If SomeClass is always a class, the A in <B extends SomeClass & A> can only be an interface, because there is no multiple inheritance in Java. The only way & A can be satisfied is if A is an interface.

    0 讨论(0)
  • 2021-02-20 06:23

    I think the problem here is that you want to return a B from this method.

    You specify B as a type parameter, but it never appears anywhere else in the method signature.

    How is the compiler supposed to infer the return type from the arguments????

    There is no opportunity for the client code to specify what B is.

    It seems like you should return either a SomeClass or an A.

    Either one can be a B under the hood, but should appear as a SomeClass or an A to the client code.

    0 讨论(0)
  • 2021-02-20 06:27

    It's impossible to impose such a compile-time restriction. Generic type parameters are stand-ins for reference types; they make no distinction between class types and interface types. The fact that additional bounds in a type parameter's declaration must be interface types is merely incidental - your strategy to leverage this as a means to impute a type as an interface was clever, but it's defeated by the limitation that type parameters can't be used in multiple bounds.

    Your only options are to settle for a runtime check using Class.isInterface() like Louis Wasserman pointed out, or to leave it up to the caller to be responsible with what it passes in. Either way, make sure to clearly document the method's expectations and behavior.


    B is intended to be a placeholder for a wildcard, so that the client can get a single object that is both a SomeClass and an A without having to do casting based on trust. The client will not have access to the name of the actual class that implements SomeClass and A

    This seems like a contradiction to me. There's no point to declaring B if the caller can't possibly know what it evaluates to. Remember: the caller of a generic method provides its type arguments. So a caller deciding B without anything to base it on can only be guessing - and that can never be type-safe.

    It seems like what you really want your method to return is some type that is both a SomeClass and an A, but this is tricky because they don't share a common supertype:

    public static <A> SomeClass&A makeSomeClass(A thing) {...}
    

    (this is nonsensical syntax for demonstration purposes only)

    As a workaround, consider alternative ways to represent both a SomeClass and some interface type. For example the candidate interfaces could have a common method for returning a SomeClass:

    public interface IsSomeClass {
        SomeClass asSomeClass();
    }
    
    public interface Foo extends IsSomeClass { }
    

    The implementation of asSomeClass would in fact just return this. Then you could do:

    public static <A extends IsSomeClass> A makeSomeClass(Class<A> type) {...}
    

    And the caller of that method would be able to use the returned object as either type:

    final Foo foo = makeSomeClass(Foo.class);
    final SomeClass someClass = foo.asSomeClass();
    

    If the interfaces themselves can't be modified, then another option is to use a wrapper class and composition instead:

    final class SomeClassWrapper<A> {
    
        private final SomeClass someClass;
        private final A a;
    
        //constructor and getters, etc.
    }
    

    And your method would return a wrapper instance instead, assigning the implementation instance to both someClass and a:

    public static <A> SomeClassWrapper<A> makeSomeClass(Class<A> type) {...}
    
    0 讨论(0)
提交回复
热议问题