2

I'm sorry, I can't seem to form a better sentence to ask this question. I'll try to clarify:

My class (currently an enum, but porting it to a class isn't an issue if it resolves this) has a Class field that denotes the type that it will dynamically instantiate at runtime.

This type must extend the Fragment class (Android) and also implement MyInterface.

<F extends Fragment & MyInterface>

How do I define this in code?

What works currently is an incomplete solution, which accepts any Fragment regardless of whether it implements MyInterface:

public enum Something {
  Value1 (OneFragmentInterfaceImplementor.class),
  Value2 (AnotherFragmentInterfaceImplementor.class);

  public final Class<? extends Fragment> fragment;

  private Something (final Class<? extends Fragment> fragmentClass) {
    fragment = fragmentClass;
  }
}

What I really want, though is that this class not only extends Fragment, but also implements MyInterface.

I want the correct form of below:

public <F extends Fragment & MyInterface> enum Something {
  Value1 (OneFragmentInterfaceImplementor.class),
  Value2 (AnotherFragmentInterfaceImplementor.class);

  public final Class<F> fragment;

  private Something (final Class<F> fragmentClass) {
    fragment = fragmentClass;
  }
}

Am I asking for the impossible here?

Update A great suggestion was to create an abstract Fragment that implements the interface. Unfortunately, this won't work in my specific use-case because some of these fragments extend other already implemented fragments.

copolii
  • 14,208
  • 10
  • 51
  • 80

2 Answers2

5

For use within an enum, which cannot take generic type parameters, create an abstract class that extends Fragment and implements MyInterface. Make your implementations extend this class. And use that with Class.

private final Class<AbstractClassThatExtendsFragmentAndImplementsMyInterface> fragment = ...;

You stated

Unfortunately, this won't work in my specific use-case because some of these fragments extend other already implemented fragments.

An alternative (half-)solution is to have the field declared with just one bound, but the parameter in the constructor have two. I say half solution because you won't be able to get the type bounds when accessing the Class field.

public enum Something {
    Value1(OneFragmentInterfaceImplementor.class), Value2(
            AnotherFragmentInterfaceImplementor.class);

    public final Class<? extends Fragment> fragment;

    private <T extends Fragment & Interface> Something(final Class<T> fragmentClass) {
        fragment = fragmentClass;
    }
}

If you can use a class, then you can declare

public class Example<T extends Fragment & MyInterface> {
    private final Class<T> fragment = ...;
    // ...    
}
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Beautiful! I've got many red lines in the IDE right now (refactoring, don't ask), but your suggestion to apply the restrictions to the private constructor shut it right up! – copolii Mar 09 '14 at 00:06
0

You cannot pass the 'implements' clause within the 'diamond' (<>) operator as it only accepts class types. To work around the requirement you need, you can create a class (or an abstract class if you do not want your users to create objects of this type) to extend Fragment and implement interface and then pass this within the diamond operator. Simply put:

class Holder extends Fragment implements MyInterface // Mark as abstract if user should not instantiate
public final Class<? extends Holder> fragment;
ucsunil
  • 7,378
  • 1
  • 27
  • 32
  • I've used the `` form before so I know for a fact that it works. Just not in this specific context. See here: http://stackoverflow.com/q/745756/1065197 – copolii Mar 08 '14 at 23:58