【问题标题】:Java Generics Error: inconvertible types from command line compilerJava 泛型错误:来自命令行编译器的不可转换类型
【发布时间】:2011-11-14 19:01:26
【问题描述】:

我有一些使用泛型的 Guice 绑定代码,这些代码可以从 Eclipse 的编译器编译并正常运行,但不能从 Java(命令行)编译器编译。我升级到最新的(1.7.0_01)Java SDK,但仍然出现以下错误。

[error] ...\BindCategorySelectorActivity.java:42: error: inconvertible types
[error]                                 (Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>) CategoryDataProvider.class);
[error]                                                                                                                             ^
[error]   required: Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>
[error]   found:    Class<CategoryDataProvider>
[error] 1 error
[error] {file:/.../compile:compile: javac returned nonzero exit code

相关代码:

public interface Category extends DatabaseItem {}
public class CategoryDataProvider implements 
 ListAdapterDataProvider<Row<Category>> {}
public class BindListViewHandlerWithSpecificProvider extends AbstractModule {
    public BindListViewHandlerWithSpecificProvider(
     Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>
      dataProviderClass) {}
}

@SuppressWarnings("unchecked")
// Error happens here:
final BindListViewHandlerWithSpecificProvider 
 bindListViewHandlerWithSpecificProvider = 
  new BindListViewHandlerWithSpecificProvider(
   (Class<? extends ListAdapterDataProvider<Row<? extends DatabaseItem>>>)
    CategoryDataProvider.class);

【问题讨论】:

    标签: java eclipse generics guice


    【解决方案1】:

    帮自己一个忙,做一个向上的,然后是一个向下的:

    Class<...> foo = (Class<...>)(Object)MyClass.class;
    

    问题是CDP.classClass&lt;CDP&gt; 类型,CDP 是原始类型。虽然参数化类型 C&lt;T1,...,Tn&gt; 是原始类型 C(第 4.10.2 节)的子类型,但反之则不然:C 不是 C&lt;T1,...,Tn&gt; 的子类型。由于未经检查的转换(第 5.1.9 节),这似乎是正确的。这导致了您的问题:您希望 CDP “扩展”(如 Class&lt;? extends ...&gt; 的上限)LADP&lt;Row&lt;? extends DI&gt;&gt;。情况并非如此,因为类型参数包含(第 4.5.1.1 节)是在子类型上定义的,并且不考虑未经检查的转换。

    (或者切入正题:javac 做对了。)

    【讨论】:

    • 好吧,它成功地编译了,但我不确定是否将额外的演员添加到 Object 只是掩盖了问题。 Guice 在尝试绑定时崩溃并出现空指针异常。其报告的行正在访问bindListViewHandlerWithSpecificProvider。请记住,这些相同的代码在 Eclipse 中编译和执行时不会出错。
    • 我承认这是一种奇怪的行为。除了从sideCasting 中欺骗 javac 之外,对 Object 进行额外的强制转换没有任何作用。您应该最终得到相同的程序。
    • 您是否熟悉 Guice 添加的泛型支持,是否有更好的机制来传递参数化类型?知道 Scala 是否为传递参数化类型提供了更好的支持?
    • 我已经使用 Guice 很久了,IIRC 它使用 Super-Type-Tokens;他们是否以及如何在这里为您提供帮助,我真的不能说。 Scala 提供manifests 的效果大致相同,只是编译器会为您推断它们。不过,这不太可能对您有所帮助..
    【解决方案2】:

    我知道答案是有效的并且被接受,但我相信沮丧并不是完美的解决方案。我的代码清理也删除了过时的向下转换...

    1) eclipse 和命令行没有产生同样问题的原因是因为 eclipse 设置。转到首选项 - java - 编译器 - 错误/警告并将泛型类型(未经检查的泛型类型操作)设置为警告。然后,如果您删除@SuppressWarnings("unchecked"),您将检测到同样的问题

    2) 我遇到了类似的问题,一位朋友向我展示了另一种解决方案。要正确修复代码(无需向下转换),只需将 CategoryDataProvider.class 更改为:

    new CategoryDataProvider<Row<DatabaseItem>>().getClass()
    

    然后放回去 @SuppressWarnings("unchecked")

    【讨论】:

    • 只有当类(在本例中为 CategoryDataProvider)具有默认构造函数时,此方法才有效。在更复杂的情况下,这种方法可能需要你做大量的准备和初始化,只是为了恢复类。
    猜你喜欢
    • 2010-11-19
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多