Can I create a member variable that is a type parameter of a generic?

1.1k views Asked by At

I have a lot of proxy classes around services, and all look (almost) the same. Can I reduce code duplication somehow by using a generics singleton class, that takes the Service and Port class as type parameters?

This is my completely wrong code with what I want to get started:

public class MyProxy<S extends Service, P extends BindingProvider>
{
  private static final MyProxy<S extends Service, P extends BindingProvider> instance
      = new Proxy<S extends Service, P extends BindingProvider>();
  private S service;

  public static MyProxy<S extends Service, P extends BindingProvider> getInstance() {
    return instance;
  }

}
  • The type parameters for MyProxy I assume to be correct.
  • Can I declare a static instance singleton member variable, and how?
  • The member variable service should be more easy, can I have a type parameter as a member, anyway?
  • How about the return type of getInstance(), how to I write it?
2

There are 2 answers

7
Holger On

Here is an example for such a proxy skeleton with a single type parameter:

public class MyProxy<S extends Service> {

  private static final ConcurrentHashMap<Class<?>, MyProxy<?>> INSTANCES
      = new ConcurrentHashMap<>();

  private S service;// could be final depending on your demands
  private final Class<S> type;

  MyProxy(Class<S> serviceType, S serviceInstance) {
    service=serviceInstance;
    type=serviceType;
  }

  /**
   * Helper method for a runtime cast.
   */
  @SuppressWarnings("unchecked")
  public <S extends Service> MyProxy<S> cast(Class<S> serviceType) {
    if(serviceType!=type) throw new ClassCastException(type+" != "+serviceType);
    return (MyProxy<S>)this;
  }

  /**
   * Get the proxy for type {@code sType}.
   */
  public static <S extends Service> MyProxy<S> getInstance(Class<S> sType) {

    MyProxy<?> old=INSTANCES.get(sType);
    if(old!=null) return old.cast(sType);

    MyProxy<S> proxy=allocateNewProxy(sType);

    old=INSTANCES.putIfAbsent(sType, proxy);
    return old==null? proxy: old.cast(sType);
  }
}

So you can use it the following way:

MyProxy<A> proxyA=MyProxy.getInstance(A.class);

Assuming that A is a subclass/implementation of Service

3
Antoine Marques On

This is the code corresponding to my first comment. As i said this involves unchecked casts.

public static class MyProxy<S extends Service, P extends BindingProvider> {

    private static final MyProxy<? extends Service, ? extends BindingProvider> instance = new Proxy<Service, BindingProvider>();

    private S service;

    public static <S extends Service, P extends BindingProvider> MyProxy<S, P> getInstance() {
        return (MyProxy<S, P>) instance;
    }
}