我编写了一个简单的容器来注册一个类及其接口,并且有一个方法可以从这些信息中创建对象:
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.class
时,可以获得类型(例如,如果它是X类)X吗?也许我这样做是错误的,我需要改变一些东西才能使它工作,但是现在我想我需要得到那个类类型,那么我可以提供代理吗?
因为如果我愿意这样的话:
X.class x;
我会得到错误。所以我需要像X x;
那样写,但我只有X.class
更新
简单地解释一下,是否有可能得到这个:
X obj;
当你只有X.class
时(X.class.newInstance
它会实例化它(比如new
?),但我还不需要实例化obj)。
UPDATE2
我试过了:
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);
}
答案 0 :(得分:0)
如果我理解正确,您正在尝试实例化类X.class
的元素?如果是这种情况,您只需拨打X.class.newInstance().
答案 1 :(得分: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));
}
你不应该使用地图的类加载器,我认为你应该使用目标对象的类加载器或将适当的类加载器作为单独的参数传递。
我认为您的方法中还存在其他问题,例如不同步容器创建而不使用泛型作为代理类型。
答案 2 :(得分: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会绕过获取默认构造函数并执行该实例的新实例时抛出的异常。
问题的第二部分 :我无法理解;接口类是代理的。在上面的create
中,您可以轻松代理Class<T>
并生成(看似)T对象。您可以将代理类委托给在上面的create
中创建的T对象。