2

我编写了一个简单的容器,它注册了一个类和它的接口,并且有一个方法可以从这些信息中创建对象,如下所示:

public class DIContainer {
    protected static DIContainer instance;
    protected Hashtable<Class<?>, Class<?>> classMap;

    protected DIContainer(){
        this.classMap = new Hashtable<Class<?>, Class<?>>();
    }

    public static DIContainer getInstance(){
        if (DIContainer.instance == null)
            DIContainer.instance = new DIContainer();
        return DIContainer.instance;
    }

    public void regClass(Class<?> interf, Class<?> classToReg){
        this.classMap.put(interf, classToReg);
    }

    public Object create(Class<?> interf) throws Exception{
        if(!this.classMap.containsKey(interf))
            throw new Exception("No such class registered with "+interf.getName()+" interface");
        return this.classMap.get(interf).newInstance();

    }
}

但是我想在创建新实例之前绕过它到代理,以便它创建,所以我有这个代理类:

public class MyProxy implements InvocationHandler
{
  private Map map;
  private Object obj;
  public static Object newInstance(Map map, Object obj, Class[] interfaces)
  {
    return Proxy.newProxyInstance(map.getClass().getClassLoader(),
                                  interfaces,
                                  new MyProxy(map, obj));
  }
  public MyProxy(Map map, Object obj)
  {
    this.map = map;
    this.obj = obj;
  }
  public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
  {
    try {
      return m.invoke(obj, args);
    } catch (NoSuchMethodError e)
    { 
    //Object result;
    String methodName = m.getName();
    if (methodName.startsWith("get"))
    {
      String name = methodName.substring(methodName.indexOf("get")+3);
      return map.get(name);
    }
    else if (methodName.startsWith("set"))
    {
      String name = methodName.substring(methodName.indexOf("set")+3);
      map.put(name, args[0]);
      return null;
    }
    else if (methodName.startsWith("is"))
    {
      String name = methodName.substring(methodName.indexOf("is")+2);
      return(map.get(name));
    }
    return null;
  }
}

}

但是对于代理类我需要提供类的类型和它的接口,但我只有它的信息X.class。可以得到类型(例如,如果它是 X 类)X,当我有X.class?也许我做错了,我需要改变一些东西才能让它工作,但现在我想我需要得到那个类类型,所以我可以为代理提供它?因为如果我想这样的话:

X.class x; 我会得到错误。所以我需要这样写X x;,但我只有X.class

更新:

简单地解释一下,是否有可能得到这个:

X obj;

当你只有X.class(用X.class.newInstance它会实例​​化它(比如用new?),但我还不需要实例化 obj 时)。

更新2

我试过这个:

Object x = (Object) MyProxy.newInstance(map, this.classMap.get(interf).newInstance(), new Class[] {this.classMap.get(interf)});

但后来我得到这个错误:

Exception in thread "main" java.lang.IllegalArgumentException: class lab.X is not visible from class loader

我的 X 班看起来像这样:

public class X implements I{
    String name;
    X(){}

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }


}

它的界面是这样的:

public interface I {
    public String getName();
    public void setName(String name);
}
4

3 回答 3

0

java.lang.IllegalArgumentException:类lab.X 在类加载器中不可见

这个错误信息不是很清楚吗?您需要确保使用相同的类加载器。

在这里:

public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
    return Proxy.newProxyInstance(map.getClass().getClassLoader(),
                                  interfaces,
                                  new MyProxy(map, obj));
}

您不应该使用地图的类加载器,我认为您应该使用目标对象的类加载器或将正确的类加载器作为单独的参数传递。

我认为您的方法中还有其他问题,例如不同步您的容器创建以及不为您的代理类型使用泛型。

于 2014-01-01T16:24:12.173 回答
0

对于第一部分,类 DIContainer,最好使用:

protected final Map<Class<?>, Class<?>> classMap;

protected DIContainer() {
    classMap = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
}

public <I> void regClass(Class<I> interf, Class<? extends I> classToReg) {
    this.classMap.put(interf, classToReg);
}

public <T> T create(Class<T> interf) throws Exception {
    Class<?> implClass = classMap.get(interf);
    if (implClass == null) {
        throw new Exception("No such class registered with " + interf.getName()
            + " interface");
    }
    Constructor<?> c = implClass.getConstructor();
    c.setAccessible(true); // If default constructor not public
    return interf.cast(c.newInstance());
}
  • 安全打字,虽然仍然部分在运行时。

  • 或多或少过时的 Hashtable 被等效替换

  • 在类上调用 newInstance 会绕过在获取默认构造函数并执行该构造函数的 newInstance 时引发的异常。

问题的第二部分:我看不懂;接口类是被代理的。在create上面,您可以轻松地代理Class<T>并产生一个(看似)T 对象。您可以将代理类委托给create如上创建的 T 对象。

于 2014-01-01T16:28:24.907 回答
0

如果我理解正确,您正在尝试实例化该类的一个元素X.class?如果是这样的话,你需要做的就是打电话X.class.newInstance().

于 2014-01-01T14:02:00.747 回答