【问题标题】:Is it possible to use generics in lists in Java 1.4?是否可以在 Java 1.4 的列表中使用泛型?
【发布时间】:2023-04-11 10:16:01
【问题描述】:

我必须使用 Java 1.4 并且正在使用 arraylist 结构。现在我需要做一些重构,如果我可以使用泛型会有所帮助。目前我有这样的代码

ArrayList rows = new ArrayList();

这是一个简单的 ArrayList。但是现在“rows”变量变得越来越复杂,需要定义一个“Row”类。我现在想做一些你在 J2SE 1.5 中看到的事情

ArrayList<Row> rows = new ArrayList();

如果不使用第 3 方解决方案的一些复杂用途,通过 Google 进行的拖网搜索不会提供任何答案。在不使用 3rd 方解决方案/开源项目的情况下(如果可能),我的代码将如何更改以适应 1.4 中的这一点?

【问题讨论】:

    标签: generics java jdk1.4


    【解决方案1】:

    泛型是在 JDK 1.5 中引入的。所以你不能在 1.4 中使用它们。但是,您可以使用 JDK 1.5 编译器,但使用 -target 1.4 javac 选项将 1.4 与您的类一起使用,同时保留 -source 1.5 选项以指示您的源代码与 1.5 兼容。在这种情况下,您可以使用泛型,因为它们不应该影响结果类。​​

    See the section on Cross-Compilation Options

    【讨论】:

    • 如果是泛型,是的,因为它们对字节码没有影响。
    • 所以可以告诉编译器使用 1.5 的语法,但编译器会生成与 1.4 兼容的类文件?我将使用的 Web 服务器上的 jvm 需要 1.4 的运行时间。尝试完成此操作的好处是防止由于转换问题导致的运行时错误。 (不得不重新添加此评论,因为它在 5 分钟后被锁定)
    • 抱歉听起来像个菜鸟,但我非常感谢您引用一个演示 Eclipse 配置的链接。
    • 对不起,我不经常使用 Eclipse。而且我在那里看不到任何明显的东西。要生成最终工件,您可能应该使用一些脚本工具(ant、maven 等)。但是,如果您需要 Eclipse,我建议您发布另一个问题。
    【解决方案2】:

    泛型倾向于解决我认为在 Java 1.4 或更早版本中处理集合时的“幼稚转换”问题。在 Java 1.5+ 中,您放置的行:

    ArrayList<Row> rows = new ArrayList();
    

    会发出警告,正确的通用代码是

    ArrayList<Row> rows = new ArrayList<Row>();
    

    这告诉编译器你的 ArrayList 对象应该只包含 Row 类型。

    但是,由于 Java 1.5 向后兼容大量不包含该语法的库,而是您以前的代码:

    ArrayList rows = new ArrayList();
    

    泛型显然不适用于这些旧库 - 因此泛型只是 编译时间 选项 - 1.5 和 1.4 类实际上是等效的(减去以后添加的任何内部重构/新方法),因为它们实际上是处理任何 Object 类型的 ArrayList 实现。

    1.5 代码只是为您添加了直接转换。

    在 1.4 代码中,假设您想要遍历 ArrayList。执行此操作的天真转换方式如下:

    for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
        Row row = (Row) rowIterator.next();
        // Do something with the row.
    }
    

    Java 1.5 的代码完全等同于 naive cast 版本。事实是,您告诉编译器它一行并为您执行该代码。因此,语法糖的好处更好(这对每个循环语法都使用了更新的语法,但它会生成与上述循环相同的代码):

    for(Row row : rows) {
       // Do something with the row
    }
    

    因此,如果您想使用仅包含行的 ArrayList,您仍然可以。但是没有办法让编译器检查 ArrayList 只包含所有行(尽管,即使编译器提供了这种检查,仍然可以发送一个ArrayList 包含其他类型的对象,因为 ArrayList 仍然只真正处理 Object 类型,并且泛型在运行时被删除 - 剩下的只是你不再看到的幼稚的转换代码。

    非天真的变体是检查每个实例并自己抛出一个带有信息性消息的 ClassCastException(而不是让程序使用其默认消息抛出一个):

    for(Iterator rowIterator = rows.iterator(); rowIterator.hasNext(); ) {
        Object shouldBeRow = rowIterator.next();
        if(!(shouldBeRow instanceof Row)) {
            throw new ClassCastException("The object " + shouldBeRow + " is not an instance of Row - only Rows should be present in the list!");
        }
        Row row = (Row) shouldBeRow;
        // Do something with the row.
    }
    

    但是,通常没有人这样做 - 好的文档可以解决这个问题,因为它将提供正确集合的负担放在调用者身上,因此您可以让 JVM 抛出 ClassCastException。

    【讨论】:

      【解决方案3】:

      是的,你可以。使用 1.5 编译器,并使用

      javac -target jsr14 ............
      

      这将生成 java 1.4 类,但允许泛型。

      此开关只能用于非字节码可见的 1.5 功能。例如,您不能使用 Enums 或 1.5 中引入的新方法。但是泛型很好,因为它们并没有真正存在于字节码中。

      【讨论】:

        【解决方案4】:

        不,您不能在 JDK 1.4 中使用它们。它们是在 JDK1.5 中引入的

        【讨论】:

          【解决方案5】:

          你所要做的就是施放它们。如果您将“错误”类型放入列表中,这可能会导致运行时异常。

          Row arow = (Row) rows.get(0);
          
          for ($i=0; i<rows.size(); $i++){
              Row element = (Row) rows.get($i);
              element.printCells();
              (...)
          }
          

          【讨论】:

          • 嘿wtf。另一个人用 60 行告诉了你我在 4 中告诉你的内容。我会向你推荐 Joshua Bloch 的“有效 Java”,仅此而已。
          猜你喜欢
          • 1970-01-01
          • 2013-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多