Что не так с использованием примитивного массива в качестве фактического параметра типа в Java 5?

Я пытаюсь скомпилировать код, например, используя JDK1.5.0_u22. Я получаю две ошибки компиляции (ниже). Он отлично работает с JDK1.6.0u30, но мой проект ограничен Java 5. Он также отлично работает, если я repleace float с классом-оболочкой Float. Кто-нибудь знает, что здесь происходит? Простая ошибка или какое-то общее ограничение на использование примитивных типов массивов в общих ситуациях?

import java.util.*;
public class A {
   public static void main(String[] args) {
     List<float[]> list = Arrays.asList(new float[1], new float[3]);
     float[] key = new float[2];
     int index = Collections.binarySearch(list, key, new Comparator<float[]>() {
        public int compare(float[] f1, float[] f2) {
           return f1.length - f2.length;
        }
     });
     System.out.println(index);
   }
}

Ошибки компиляции:

C:\Users\mravn\Desktop>"c:\Program Files\Java\jdk1.5.0_22"\bin\javac A.java
A.java:4: incompatible types
found   : java.util.List<<nulltype>[]>
required: java.util.List<float[]>
       List<float[]> list = Arrays.asList(new float[1], new float[3]);
                                       ^
A.java:6: cannot find symbol
symbol  : method binarySearch(java.util.List<float[]>,float[],<anonymous java.util.Comparator<float[]>>)
location: class java.util.Collections
     int index = Collections.binarySearch(list, key, new Comparator<float[]>() {
                            ^
2 errors

C:\Users\mravn\Desktop>

Ответ 1

Я собираюсь дать ответ на 1-ю ошибку компилятора и продолжить копать, чтобы узнать, могу ли я найти ту, которая была для второй ошибки компилятора...

Выполнение следующего сам по себе не вызывает ошибок с помощью jdk1.5.0_22:

System.out.println(Arrays.asList(new float[1]).size());

Запуск этого сам по себе...

System.out.println(Arrays.asList(new float[1], new float[3]).size());

создает эту неприятную ошибку компилятора...

An exception has occurred in the compiler (1.5.0_22). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport)  after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report.  Thank you.
java.lang.AssertionError: unexpected type: <nulltype>
        at com.sun.tools.javac.tree.TreeMaker.Type(TreeMaker.java:531)
        at com.sun.tools.javac.tree.TreeMaker.Type(TreeMaker.java:525)
        at com.sun.tools.javac.comp.Lower.boxArgs(Lower.java:2510)
        at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2420)
        at com.sun.tools.javac.tree.Tree$Apply.accept(Tree.java:813)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.comp.Lower.visitSelect(Lower.java:3019)
        at com.sun.tools.javac.tree.Tree$Select.accept(Tree.java:987)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2474)
        at com.sun.tools.javac.tree.Tree$Apply.accept(Tree.java:813)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1893)
        at com.sun.tools.javac.comp.Lower.boxArgs(Lower.java:2517)
        at com.sun.tools.javac.comp.Lower.visitApply(Lower.java:2420)
        at com.sun.tools.javac.tree.Tree$Apply.accept(Tree.java:813)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.tree.TreeTranslator.visitExec(TreeTranslator.java:227)
        at com.sun.tools.javac.tree.Tree$Exec.accept(Tree.java:728)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.tree.TreeTranslator.translate(TreeTranslator.java:54)
        at com.sun.tools.javac.tree.TreeTranslator.visitBlock(TreeTranslator.java:145)
        at com.sun.tools.javac.comp.Lower.visitBlock(Lower.java:2933)
        at com.sun.tools.javac.tree.Tree$Block.accept(Tree.java:535)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.tree.TreeTranslator.visitMethodDef(TreeTranslator.java:129)
        at com.sun.tools.javac.comp.Lower.visitMethodDefInternal(Lower.java:2267)
        at com.sun.tools.javac.comp.Lower.visitMethodDef(Lower.java:2186)
        at com.sun.tools.javac.tree.Tree$MethodDef.accept(Tree.java:478)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.comp.Lower.visitClassDef(Lower.java:1989)
        at com.sun.tools.javac.tree.Tree$ClassDef.accept(Tree.java:434)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1881)
        at com.sun.tools.javac.comp.Lower.translate(Lower.java:1901)
        at com.sun.tools.javac.comp.Lower.translateTopLevelClass(Lower.java:3070)
        at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:487)
        at com.sun.tools.javac.main.Main.compile(Main.java:592)

Итак, я последовал советам компиляторов и сделал некоторые поиски в базе данных Oracle bug и нашел ошибку, выполнив поиск "java.lang.AssertionError: неожиданный тип:". Вы можете проверить это здесь: Примитивные массивы и вывод varargs приводят к сбою в TreeMaker.Type(TreeMaker.java:531)

Использование класса оболочки Float - это работа, которую вы обнаружили.

EDIT - ответ для второй ошибки компилятора

Я считаю, что ошибка второго компилятора была ошибкой, и я отправил ее в Bug Database

Я смог скомпилировать следующий список, ключ и компаратор самостоятельно без ошибок компилятора:

List<float[]> list=new ArrayList<float[]>();
list.add(new float[] {0.0f});
list.add(new float[] {1.0f});

float[] key = new float[2];

Comparator<float[]> c = new Comparator<float[]>() {
    public int compare(float[] f1, float[] f2) { 
        return f1.length - f2.length;
    }
};

Когда я пытаюсь запустить "Collections.binarySearch(list, key, c)" с ними, я получаю ошибку "не могу найти символ". Если я изменил "float" на "Float", он скомпилируется в обоих случаях.

Я считаю, что список, ключ и компаратор, который я написал выше, полностью выполняет бинарный поисковый контракт в соответствии с Java 5 spec на нем

Ответ 2

Обходной путь может заключаться в компиляции с JDK 6 и установке -target 1.5, тогда можно будет запустить его с помощью jdk 1.5.0_22 (попробованный в ящике linux).

Ответ 3

Дженерики не обрабатывают примитивы последовательно. Это связано с тем, что Generics - это просто компиляция времени для одного класса.