2009-04-25 75 views
6

我在玩一些代码katas,并试图在同一时间更好地理解java泛型。我有这样一个打印数组的方法,就像我喜欢看到它们一样,并且我有几个帮助器方法,它们接受'东西'和索引的数组,并返回索引上方或下方'东西'的数组这是一个二进制搜索算法)。你可以传递一个int数组到Java中的泛型方法吗?

两个问题,

#1我能避免在splitBottom和splitTop投至T?它感觉不对,或者我以错误的方式去做(不要告诉我使用python或其他东西..))

#2我是否必须编写单独的方法来处理原语数组还是有更好的解决方案?

public class Util { 

    public static <T> void print(T[] array) { 
     System.out.print("{"); 
     for (int i = 0; i < array.length; i++) { 
      System.out.print(array[i]); 
      if (i < array.length - 1) { 
       System.out.print(", "); 
      } 
     } 
     System.out.println("}"); 
    } 

    public static <T> T[] splitTop(T[] array, int index) { 
     Object[] result = new Object[array.length - index - 1]; 
     System.arraycopy(array, index + 1, result, 0, result.length); 
     return (T[]) result; 
    } 

    public static <T> T[] splitBottom(T[] array, int index) { 
     Object[] result = new Object[index]; 
     System.arraycopy(array, 0, result, 0, index); 
     return (T[]) result; 
    } 

    public static void main(String[] args) { 

     Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     print(integerArray); 
     print(splitBottom(integerArray, 3)); 
     print(splitTop(integerArray, 3)); 

     String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}; 
     print(stringArray); 
     print(splitBottom(stringArray, 3)); 
     print(splitTop(stringArray, 3)); 

     int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     // ??? 
    } 
} 

回答

9

泛型不能以一致的方式处理原语。这是因为泛型不像C++中的模板,它只是一个编译时间添加到一个类中。

当编译泛型时,最终以上例中的Object []作为实现类型。作为int []和byte []等,不要扩展Object [],即使所涉及的代码是相同的,也不能互换使用它们(再泛型不是模板)

唯一的类int []和Object [] share是Object。您可以将上述方法Object写为类型(请参阅System.arraycopy,Array.getLength,Array.get,Array.set)

1

问题1: Casting数组不会像您期望的那样工作。一个String是一个Object,但是一个String数组不是Object数组。

尝试使用类似:

public static <T> T[] splitTop(T[] array, int index) { 
    T[] result = Arrays.copyOfRange(array, index + 1, array.length); 
    return result; 
} 

问题2: 基本类型数组我的功能明显也不起作用。没有优雅的解决方案 - 例如查看Arrays库,它对每个基本类型都有几个基本相同方法的副本。

+0

你不能这样做泛型 - 这会导致不兼容的类型错误。 – hbw 2009-04-25 07:27:52

3

1我可以避免在splitBottom和splitTop中转换为T吗?它不 感觉不对,不然我要对此 错误的方式(不要告诉我用 Python或东西..;))

您不仅可以无法避免这一点,但你不应该这样做。在Java中,不同类型的数组实际上是不同的运行时类型。创建为Object[]的数组不能指定给AnythingElse []的变量。这里的转换不会立即失败,因为在泛型中类型T会被删除,但是稍后它会在代码尝试将它用作Something []时抛出ClassCastException,如您所承诺的那样,但事实并非如此。

解决方案是在Java 6及更高版本中使用Arrays.copyOf...方法,或者如果您使用较早版本的Java,请使用Reflection创建正确类型的数组。例如,

T [] result =(T [])Array.newInstance(array.getClass()。getComponentType(),size);

2我必须编写单独的方法来处理原始数组吗?或者是 还有更好的解决方案吗?

这可能是最好的编写单独的方法。在Java中,基元类型的数组与引用类型的数组完全分离;并没有很好的方式与他们合作。

有可能使用反射来同时处理两者。反射有Array.get()Array.set()方法,这些方法可以用于原始数组和参考数组。但是,通过这样做,您会失去类型安全性,因为基本数组和参考数组的唯一超类型为Object

1

Java不允许以类型安全的方式构建泛型数组。改为使用通用序列类型(例如,java.util.List)。

以下是我会写你的测试程序,使用通用的容器类fj.data.Stream

import fj.data.Stream; 
import static fj.data.Stream.range; 

// ... 

public int[] intArray(Stream<Integer> s) { 
    return s.toArray(Integer.class).array() 
} 

public static void main(String[] args) { 
    Stream<Integer> integerStream = range(1, 10); 
    print(intArray(integerStream)); 
    print(intArray(integerStream.take(3))); 
    print(intArray(integerStream.drop(3))); 

    // ... 
} 
0

你有两个问题,你要完成的任务。

首先,您正尝试使用基本类型,它们实际上并不从Object继承。这会弄乱事情。如果你真的需要这样做,明确地使用Integer而不是int等。

第二个也是更大的问题是Java泛型有类型擦除。这意味着在运行时,您实际上不能引用泛型的类型。这样做的目的是允许您混合通用支持代码和非通用支持代码,并且最终(恕我直言)成为Java开发人员头疼的主要来源,另一个证据表明泛型从第1天开始就应该在Java中。我建议您阅读关于它的tutorial中的部分,它会使这个问题更清楚。

0

您可能必须将原语包装到相应的集合中。

我也建议看看Trove原始集合(http://trove.starlight-systems.com)。这与您的泛型问题无关,但可能相当有趣。

相关问题