【问题标题】:Introducing generics to Java code without breaking the build在不破坏构建的情况下向 Java 代码引入泛型
【发布时间】:2008-11-13 16:24:27
【问题描述】:

以下代码无法编译:

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<?> list = new MyList<Object>();
        Class<?> clazz = list.get(0);

        // Does not compile with reason 
        // "Type mismatch: cannot convert from Object to Class"
        MyList list2 = new MyList();
        Class clazz2 = list2.get(0);
    }
    static class MyList<T> extends ArrayList<Class<T>> {
    }
}

我想这样做是为了在不破坏构建的情况下将泛型引入旧代码。

这是编译器(eclipse 和 javac)中的错误还是我在这里遗漏了什么?将泛型引入 MyList 还有哪些其他可能性?

编辑

澄清:

我有通用类

public class MyList extends ArrayList<MyObject> {}

public class MyObject {}

和使用 MyList 的代码

MyList list = new MyList();
...
MyObject o = list.get(0);

现在在开发过程中,我看到我想向 MyObject 引入泛型

public class MyObject<T> {}

现在我想在 MyList 中也有这个新的通用东西

public class MyList<T> extends ArrayList<MyObject<T>> {}

但这确实破坏了我的构建。有意思

public class MyList<T> extends ArrayList<MyObject<T>> {
    public MyObject<T> get(int i) {
        return super.get(i);
    }
}

将允许旧代码

MyList list = new MyList();
...
MyObject o = list.get(0);

编译。

好吧,似乎当我介绍这个泛型时,我将不得不将所有对 MyList 的调用更改为泛型形式。我希望旧代码只引入警告而不是错误。

【问题讨论】:

  • 如果您提供编译错误以及代码会有所帮助。
  • 编译错误在示例中的注释中。

标签: java generics


【解决方案1】:

我认为您不太了解泛型的工作原理。

MyList<?> list = new MyList<Object>();
Class<String> clazz= list.get(0);

此代码 sn-p 无法编译,因为您告诉编译器 list 将保存 Class&lt;Object&gt; 类型 - 然后在下一行中您期望它返回 Class&lt;String&gt;。 Java 中的泛型系统无法像您想象的那样基于继承转换与泛型一起使用的类型。

如果您希望 list 持有 Class&lt;String&gt;,那么您需要将其声明为 - 或者,如果您希望它能够持有任何类型,那么您不能在没有强制转换的情况下执行第二行。

MyList<String> list = new MyList<String>();
Class<String> clazz = list.get(0);

MyList<?> list = new MyList<Object>();
//generates a warning about an unchecked cast
Class<String> clazz = (Class<String>) list.get(0);

第二个代码 sn -p 不起作用,因为当你使用原始类型时,你仍然需要将 get() 返回的 Object 强制转换为你正在使用的声明类型(一直都是这样)。

MyList list2 = new MyList();
Class clazz2 = (Class) list2.get(0);

【讨论】:

  • 我想你最后没有看到类 MyList 的声明:static class MyList extends ArrayList>。定义了 MyList 采用 Class-Objects.
  • 对,我在最后发现了这一点 - 但他希望 MyList 可以转换为 MyList,但事实并非如此。
  • 不,我不希望 MyList 可以转换为 MyList。我希望 MyList 可转换为 MyList>。抱歉,我的示例出错了。
  • 好吧,您的更正示例,我的第二个答案仍然适用 - 原始 List 上的 get() 方法返回一个对象,因此您需要将其显式转换为一个类。
【解决方案2】:

我在这台机器上没有编译器,但这应该可以工作。

public class GenericsTest {    
    public static void main(String[] args) {
        MyList<Object> list = new MyList<Object>();
        Class<?> clazz= list.get(0);

    }


    static class MyList<T> extends ArrayList<Class<? extends T>> {
    }
}

【讨论】:

  • 是的。存在运行时错误,因为它在空列表上调用 get() 但代码编译。
  • 是的,您的代码可以编译,但“Class clazz = list.get(0);”都没有也不是“MyList list = new MyList(); Class clazz = list.get(0);”。 “类 clazz = list.get(0);”会起作用,但这不是预期用途。
【解决方案3】:

在您的示例中,MyList 是您想要更新以支持泛型的旧代码吗?如果是这样,我的列表应该包含什么类型的对象?

正如这里在别处提到的,编译错误是有效的。这是因为在访问原始列表时没有将 get 强制转换为 Class。因此代码试图将一个对象分配给一个类的引用。相当于这样:

Object o = new Object();
Class c = o;

根本无法编译。此外,要充分利用泛型,您应该使用 Class> 而不是 Class。

【讨论】:

    【解决方案4】:

    在您的示例中,第二个示例不起作用,因为您没有使用泛型,因此这意味着 get() 方法将返回一个 Object,您需要将其转换为 Class。当您没有为 MyList 指定类型时:

    MyList list2 = new MyList();

    那么你就失去了泛型的优势,你需要像过去一样在调用 get() 方法时强制转换对象。

    【讨论】:

      【解决方案5】:

      你试过了吗:

      Class clazz2 = list2.get(0).getClass();
      

      阅读: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#getClass()

      【讨论】:

      • 但这不一样! String.class != String.class.getClass()
      猜你喜欢
      • 1970-01-01
      • 2017-12-17
      • 2018-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多