问题是这样的,由于两个项目要分开开发,第一个项目要调用另一个项目中的函数,我使用了反射调用,但是返回的数据类型需要自定义,这样我就自定义了class A,然后编译打包了A,构成一个A.jar包,然后发布给另一个项目来直接使用这个数据类型,第一个项目反射调用了第二个项目的某个方法,要返回数据类型A,来供第一个项目使用,第一个项目也包含了A这个jar包;但是结果有问题,反射调用了第二个项目的方法返回的数据Object不能cast 到A;抛出异常,A 无法cast to A;请问下,这个需要怎么处理呢?是因为A.jar的问题,还是java不支持这样的操作?谢谢各位~!Java应用

解决方案 »

  1.   

    我没看明白,是不是这样
    你有项目A和项目B,还有一个项目里包含了class Type,先叫它项目T
    B包含了一个方法:public T method();
    A和B都有到T的引用,也就是T分别包含在A和B的classpath里,然后A反射调用B的method,反射API返回一个Object,但是不能被cast到T?
      

  2.   

    A项目使用了数据类型T,B也使用了数据类型T,A调用B的方法,返回一个T类型数据,但是A不能cast 到T,这个T是定义在一个jar里面的,A\B都是包含了这个jar包
      

  3.   

    如果package名都相同的话,那应该是这个类分别是两个不同的类加载器加载的。
    package不相同的话,应该是存在两个类了。
      

  4.   

    你说的是自定义数据类型T的package名还是两个A\B项目的package名?
      

  5.   

    我做了这么一个小实验:
    ProjectA:
    public class ClassA {
      public static void main(final String[] args)
              throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException,
              MalformedURLException, InstantiationException {
        URLClassLoader urlClassLoader = new URLClassLoader(
                new URL[]{new File("/Users/xxx/testJavaProject/projectB/ClassB.jar").toURI().toURL()},
                new ClassA().getClass().getClassLoader());
        Class<?> classB = Class.forName("ClassB", true, urlClassLoader);
        Object objectB = classB.newInstance();
        Method method = classB.getDeclaredMethod("method");
        Object result = method.invoke(objectB);
        Type t = (Type) result;
        System.out.println(t.toString());
      }
    }ProjectB:
    public class ClassB {
      public final Type method() {
        return new Type();
      }
    }ProjectT:
    public class Type {
    }编译过程:
    1. javac Type.java; jar -cf Type.jar Type.class
    2. javac -classpath ../Type/Type.jar ClassB.java; jar -cf ClassB.jar ClassB.class运行:
    java -cp .:../Type/Type.jar ClassA输出:Type@75da931b目录切换我就省略了不知道楼主的过程是不是一样
      

  6.   

    居然不能编辑自己的帖子,我算服了。编译过程中漏了一步,编译出ClassA.class,不过楼主应该懂另外没有把代码放进语法高亮框,反正很简单的就将就一下吧~
      

  7.   

    哦。如果那个不能强制类型转换的对象,对应的是同一个类的话,或者说,是同一个类文件的话。
    那么,无法强制类型转换,一定是因为,他们(强制转换的类型类和当前对象)不是同一个类加载器对象加载的。解决这个问题,可以从几个方面去入手:
    1. 如果两个项目,没有涉及到多线程或者异步处理的框架结构,那么,可以在反射的时候,都使用当前线程上下文环境的类加载器对象,来加载所用到的类,和创建对象。
    2. 如果涉及到多线程,那么,两个项目在反射调用之前,都应当用系统加载器将公共的类(本例中A这个类)加载进来,注意,要预先加载,这个预先加载的代码,不要出现在反射代码的那个类,要在这个类之前就预先加载进来。
    3. 一般处理这类情况的方式,是这样的:
    A:需求所要完成的应该是一个功能接口的开发,所以,涉及到两种类型的类,
          一种类定义操作的方法列表,另一种定义方法的参数和返回值;
    B:定义操作的类,我们要抽象出接口类,接口类的加载都用系统类加载器进行加载,而接口类的实现类,可以用系统类加载器的下属类加载器加载。(下属类不是子类,不是继承关系,一般是应用程序自定义的类加载器)
    C:定义参数和返回值的类,通常也和接口类所使用的加载器对象相同;
    D:类加载器的加载顺序是,先判断父级加载器是否加载,如已加载就用已加载的,未加载再由当前对象加载。
      

  8.   

    这件事情最简单的办法,就是不使用反射,用工厂模式配合接口实现 替代 反射调用。你定义如下几个类,提供给对方,让其把接口类实现(创建实现类,实现接口方法)
    public interface MethodList {
    Return4Method1 method1(Param4Method1 params);
    void method2(Param4Method2 params);
    }
    public class Return4Method1 { private Object value;

    public Object getValue() {
    return value;
    }
    public void setValue(Object value) {
    this.value = value;
    }
    }
    public class Param4Method1 { private Object args; public Object getArgs() {
    return args;
    }
    public void setArgs(Object args) {
    this.args = args;
    }
    }
    public class Param4Method2 { private Object args; public Object getArgs() {
    return args;
    }
    public void setArgs(Object args) {
    this.args = args;
    }
    }
    public interface MethodListFactory { MethodList createInstance();

    }
    接下来,对方要创建如下两个实现类。
    public class DefaultMethodList implements MethodList { public Return4Method1 method1(Param4Method1 params) {
    Return4Method1 value = new Return4Method1();
    //do something ...
    return value;
    } public void method2(Param4Method2 params) {
    // do some other things ...
    }}
    public class DefaultMethodListFactory implements MethodListFactory { public MethodList createInstance() {
    // 创建接口的实现类对象。
    return null;
    }}
    具体的代码,你不用管。
    你只要关心,怎么拿到那个DefaultMethodListFactory类的对象即可。
    如果两个项目都集成在spring下,可以使用spring来获得对象;
    如果对方提供DefaultMethodListFactory的public的构造器,可以直接new一个出来。
    之后的使用,不用我废话了吧,以前不都吵吵着什么面向接口编程么,接下来的代码就是这样的了。