在对象上调用一个我不知道的类型的方法

时间:2009-09-26 01:03:41

标签: java generics

我有一个通用的PostProcessor接口,如下所示:

public interface PostProcessor<T> {
    public void process( T t );
}

我正在为通用列表实现一个PostProcessor,它将为列表中的每个项调用一个合适的后处理器。

public class ListPostProcessor implements PostProcessor<List<?>> {
    public void process(List<?> t) {
        final PostProcessor<?> p = ...;

        for( Object o : t )
            if(p!=null) 
                p.process(o); // BUG can't pass type Object to process()
    }

}

忽略设置p(用...表示)的魔力,我的问题是我无法拨打process(o),因为oObject ,而不是?。但我无法将o转换为正确的类型,因为我不知道在编译时该类型是什么。

如何在列表中的每个项目上调用process()方法,而不必为可能使用的每种类型的类型实例化单独的ListPostProcessor

更新

根据下面flicken的建议,我尝试使用<? extends Object>

public class ListPostProcessor implements PostProcessor<List<? extends Object>> {
    public void process(List<? extends Object> list) {
        final PostProcessor<? extends Object> p = ... ;

        if( p!=null )
            for( Object o : list )
                p.process(o);  // BUG still a problem
    }
}

但是我从Eclipse得到了同样的错误:

The method process(capture#3-of ? extends Object) in the type PostProcessor<capture#3-of ? extends Object> is not applicable for the arguments (Object)

7 个答案:

答案 0 :(得分:2)

要在Generic类型中保持一致,您可以根据您的所有规范所遵循的单一类型指定PostProcessor:

   public interface PostProcessor<U> {
      public void process( U u );
   }

   public class ListPostProcessor<T> implements PostProcessor<List<T>> {
      public void process(List<T> t) {
        final PostProcessor<T> p = ...;
        for (T o : t) {
            if (p != null) {
              p.process(o);
            }
         }
      }
   }

如果您想拥有一个可以处理任何类型的Object的ListPostProcessor实例,您可以根据需要在类层次结构中将其实例化为深/浅:

new ListPostProcessor<MyBaseClass>();

会做到这一点。将会:

new ListPostPorcessor<Object>();

后者类似于根本不使用Generics,它允许您执行您请求的操作 - 允许任何类型的Object由Genericized类处理。

答案 1 :(得分:1)

而不是Object,使用一个名为processable的接口来声明process()方法,并且列表成员必须是其子级

答案 2 :(得分:1)

使用&lt; ? extends Object&gt;

 public class ListPostProcessor implements PostProcessor<List<? extends Object>> {
      ...
 }

答案 3 :(得分:0)

我注意到这不是C#代码,但是有没有办法使用反射,这会是一个很好的反射应用吗?

答案 4 :(得分:0)

实际上,在进一步思考时,最好的解决办法是做以下事情:

public class ListPostProcessor implements PostProcessor<List<?>> {
    @SuppressWarnings("unchecked")
    public void process(List<?> t) {
        final PostProcessor p = ...;

        for( Object o : t )
            if(p!=null) 
                p.process(o);
    }

}

之前的最佳答案(akf建议使用ListPostProcessor implements PostProcessor<List<Object>>放弃了List的类型,我实际需要为PostProcessor找到合适的p。此解决方案保留了该类型信息。

答案 5 :(得分:0)

我正在寻求一系列的评论,但是我越是看到它越少,我认为这将起作用...永远......至少不是现在的形式。您的提案中存在两个主要问题:

1-擦除泛型。处理器是一个通用类,它针对要处理的特定类型进行实例化。只要你喂它那种类型就可以了。另一方面,ListPostProcessor被声明为处理器类型,它处理任何事物的列表但转过身并希望获得列表内容所需的确切处理器类型。没有任何泛型杂技会允许你这样做,部分原因是Java编写的泛型在编译后会被删除而只留下原始类型。因此,一旦程序运行,所有泛型声明都将消失。

2- Rutime类型路由:这是伤害的部分:什么机制决定如何将数据路由到适当的处理器?您是否拥有所有可能类型的处理器或扩展Object的所有可能类型?怎么知道要得到什么样的处理器?处理器做了什么呢?我认为可以创建一个处理器,扩展特定类型或类型结构的接口,并使用自动类型转换泛型提供立即开始处理相应的类型。在ListPostProcessor的情况下,它不知道要调用哪种处理器类型,首先是因为泛型类型信息被擦除了,除了ListPostProcessor之外你还需要某种工厂或调度程序来调用正确的处理器。

3-即使所有上述内容最终都有效,单个PostProcessor如何处理任何列表中的所有对象。唯一的方法是实例化一个对象的PostProcesor因此这段代码可以工作,但我想你不会真正想要的是:

  public class ListPostProcessor implements PostProcessor<List<? extends Object>>{
 public void process(List<?> t){
  final PostProcessor<Object> p = new PostProcessor<Object>(){
   public void process(Object o){
     // do stuff
     }
        };
  for (Object o : t){
   if (p != null){
                        p.process(o);
   }
  }
 }
  }

或者,如果你真的想用它自己的类型处理每个项目,那么你需要一些魔法,而PostProcessor需要在循环中。像这样:

public class ListPostProcessor implements PostProcessor<List<? extends Object>>{
 public void process(List<?> t){
  for (Object o : t){
   if (p != null){
    PostProcessor<? extends Object> p = ProcessorFactory.getAppropriateProcessor(o); 
    p.process(o);
   }
  }
 }
}

答案 6 :(得分:-1)

if(object instanceof type)....

  

哦,伟大的打字怪物,隐藏   原型的复仇 - 羞辱你自己   陷入默默无闻,离开这原始状态   世界,去禁止的星球和   那里的植物咀嚼着。   它们很甜,你会喜欢它们。

永远不会发生,要么你和巨人开关一起生活,要么去自动生存。 (自我诽谤)

我在Java研究的早期就看到了这一点,在我刚刚在巨型交换机上编写我的异常机制之前就已经在那里。

今天仍在使用它。