5

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

ArrayList rows = new ArrayList();

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

ArrayList<Row> rows = new ArrayList();

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

4

5 回答 5

9

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

请参阅交叉编译选项部分

于 2011-06-12T05:29:54.603 回答
4

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

ArrayList<Row> rows = new ArrayList();

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

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

This tells the compiler that your ArrayList object should only ever contain the Row type.

However, since Java 1.5 is backwards-compatible with huge sets of libraries that don't contain that syntax, but rather your previous code:

ArrayList rows = new ArrayList();

Generics obviously wouldn't work with these older libraries - therefore generics are only a compile time option - the 1.5 and 1.4 classes are effectively equivalent (minus any internal refactoring/new methods added later) because they are really ArrayList implementations that handle any Object type.

The 1.5 code simply adds in a direct cast for you.

In 1.4 code, say you wanted to iterate over the ArrayList. The naive cast way to do this is the following:

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

Java 1.5's code is exactly equivalent to the naive cast version. It takes the fact that you are telling the compiler that it is a row and does that code for you. So, the syntactic sugar benefits are nicer (this uses the newer for each loop syntax, but it generates the same code as the above loop):

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

So, if you want to use an ArrayList containing only rows, you still can. But there's no way to get the compiler to check that the ArrayList contains only all rows (although, even though the compiler provides this check, it is still possible to send in an ArrayList that contains other types of objects, since, again, the ArrayList still only really handles the Object type, and the generics are erased at runtime - all that remains is the naive cast code that you don't see anymore).

The non-naive variant is to check each instance and throw a ClassCastException yourself with an informative message (rather than have the program throw one with its default message):

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.
}

However, generally no one does this - good documentation can make this issue moot, as it places the burden of providing the correct collection on the caller and thus you can just have the ClassCastException thrown by the JVM.

于 2011-06-12T05:38:56.427 回答
2

Yes you can. Use a 1.5 compiler, and use

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

This will generate java 1.4 classes, but allow generics.

This switch can only be used for non byte code visible 1.5 features. For instance you can't use Enums, or new methods introduced in 1.5. But generics are fine, as they are not really present in the byte code.

于 2011-06-12T06:31:07.900 回答
0

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

于 2011-06-12T05:36:29.703 回答
-1

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

Row arow = (Row) rows.get(0);

for ($i=0; i<rows.size(); $i++){
    Row element = (Row) rows.get($i);
    element.printCells();
    (...)
}
于 2011-06-12T05:35:50.100 回答