泛型是否允许Java编译器检查映射中的键和值的类型?

时间:2009-09-24 18:39:34

标签: java generics

我处于这样一种情况,我希望有一个映射,其中键是一个接口类,相应的值是一个实现该接口的类。换句话说,键和值类型是相关的。

我当前实现的方法添加到地图中,并获取实现类的实例,如下所示:

// should be something like Class<T>, Class<? extends T>
static Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>> ();

public static <T> void add(Class<T> interfaceT,
     Class<? extends T> implementationT) {

  map.put(interfaceT, implementationT);
}

public static <T> T get(Class<T> interfaceT) {
  // cast caused by definition not complete.

  Class<T> implementationT = (Class<T>) map.get(interfaceT);

  // try catch stuff omitted
  T t = implementationT.newInstance();
  return t;
 }

我的问题是:

可以我定义了“map”变量,因此不需要get(...)方法中的强制转换?我无法使“新HashMap<Class<T>, Class<? extends T>>()”工作,所以要么是不可能的,要么我错过了一些基本的东西:)

请告知:)


编辑:事实证明Class上的asSubclass()方法做了我想要的:D

Class<?> rawClassFromMap = map.get(interfaceT);
Class<? extends T> implementationT = rawClassFromMap.asSubclass(interfaceT);

很好,implementationT的类型为“?extends T”,因为我只需要返回一个T对象。

我喜欢泛型。让我想起了Haskell ......

2 个答案:

答案 0 :(得分:4)

看起来像Josh Bloch在Chapter 5 of Effective Java (item 29).中描述的类似“Typesafe Heterogenous Container”的东西在他的情况下,他将类型(Class<T>)映射到(已经实例化的)实例(T)。

您可以使用asSubclass代替cast来执行类似操作:

final class Factory
{

  private Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();

  <T> void map(Class<T> type, Class<? extends T> impl)
  {
    map.put(type, impl.asSubclass(type));
  }

  private <T> Class<? extends T> get(Class<T> type)
  {
    Class<?> impl = map.get(type);
    if (impl == null) 
      throw new IllegalArgumentException("Unknown type: " + type);
    return impl.asSubclass(type);
  }

  <T> T create(Class<T> type) 
    throws Exception
  {
    Class<? extends T> impl = get(type);
    Constructor<? extends T> ctor = impl.getConstructor();
    return ctor.newInstance();
  }

}

答案 1 :(得分:0)

我建议Proxy。这是Java example

public interface Bike {

    public String getWheels();

    public int getSize();

}

public class MountainBike implements Bike {

    @Override
    public int getSize() {
        return 24;
    }

    @Override
    public String getWheels() {
        return "Treaded";
    }

    @Override
    public String toString() {
        String newLine = System.getProperty("line.separator");
        StringBuilder sb = new StringBuilder();
        sb.append("Type:   MOUNTAIN").append(newLine);
        sb.append("Wheels: ").append(getWheels()).append(newLine);
        sb.append("Size:   ").append(getSize()).append(newLine);
        return sb.toString();
    }

}

public class CruiserBike implements Bike {

    @Override
    public int getSize() {
        return 26;
    }

    @Override
    public String getWheels() {
        return "Smooth";
    }

    @Override
    public String toString() {
        String newLine = System.getProperty("line.separator");
        StringBuilder sb = new StringBuilder();
        sb.append("Type:   CRUISER").append(newLine);
        sb.append("Wheels: ").append(getWheels()).append(newLine);
        sb.append("Size:   ").append(getSize()).append(newLine);
        return sb.toString();
    }

}

public class BikeProxy implements InvocationHandler {

    private Object obj;

    public static Object newInstance(Object obj) 
    {
        return java.lang.reflect.Proxy.newProxyInstance(obj.getClass()
                .getClassLoader(), obj.getClass().getInterfaces(),
                new BikeProxy(obj));
    }

    public static <T> T newInstance(String className) 
    {
        try 
        {
            return (T) newInstance(Class.forName(className));
        } 
        catch (ClassNotFoundException e) 
        {
            throw new RuntimeException(e);
        }
    }

    public static <T> T newInstance(Class<T> bikeClass) 
    {
        try
        {
        return (T) java.lang.reflect.Proxy.newProxyInstance(Bike.class.getClassLoader(), new Class[]{Bike.class},
                new BikeProxy(bikeClass.newInstance()));
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    private BikeProxy(Object obj) 
    {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args)
            throws Throwable 
    {
        Object result;
        try 
        {
            result = m.invoke(obj, args);
        } 
        catch (InvocationTargetException e) 
        {
            throw e.getTargetException();
        } 
        catch (Exception e) 
        {
            throw new RuntimeException(e);
        }
        return result;
    }
}

public class ProxyTester 
{
    public static void main(String[] args) 
    {
        Bike mountainBike = BikeProxy.newInstance(MountainBike.class);
        System.out.println(mountainBike);

        Bike mountainBike2 = BikeProxy.newInstance(MountainBike.class.getName());
        System.out.println(mountainBike2);

        Bike cruiserBike = BikeProxy.newInstance(CruiserBike.class);
        System.out.println(cruiserBike);

        Bike cruiserBike2 = BikeProxy.newInstance(CruiserBike.class.getName());
        System.out.println(cruiserBike2);
    }
}