【问题标题】:Returning T[] (where T is Byte[]) to Byte[]将 T[](其中 T 是 Byte[])返回到 Byte[]
【发布时间】:2012-04-26 09:11:30
【问题描述】:

我有一个 Java JUnit 4 测试和一个创建泛型数组的泛型类。当我创建一个方法来返回这个通用数组时,我在返回它时收到一条错误消息。如果我将 ArrayList(其中 T 是按类实例化的字节)返回到 ArrayList,它将起作用。

为什么数组似乎已实例化且可用(在更复杂的类上测试)但我无法返回对该数组的引用?

错误:

java.lang.ClassCastException: [Lcom.waikato.assignment.Object; cannot be cast to [Ljava.lang.Byte;
at com.waikato.testing.TestJava.test(TestJava.java:20)

类:

public class TestClass<T> {
    T[] array;

    @SuppressWarnings("unchecked")
    public TestClass() {
        array = (T[]) new Object[32];
    }

    public T[] getArray() {
        return array;
    }

    public boolean doThing() {
        T[] t = array;

        return t == array && t != null;
    }
}

测试:

public class TestJava {

    @Test
    public void test() {
        TestClass<Byte> t = new TestClass<Byte>();
        Byte[] b = t.getArray(); // Crash caused

        assertTrue(t.doThing()); // Works when above line is removed.
        assertTrue(b.length != 0);
    }

}

【问题讨论】:

    标签: java arrays generics java-6


    【解决方案1】:

    可以通过反射构造“通用”数组:

    T[] array = (T[]) Array.newInstance(Byte.class, 32)
    

    Byte.class 替换为对所需类的引用。换句话说:

    public class TestClass<T> {
        T[] array;
    
        @SuppressWarnings("unchecked")
        public TestClass(Class<T> type) {
            array = (T[]) Array.newInstance(type, 32);
        }
    
        public T[] getArray() {
            return array;
        }
    
        public boolean doThing() {
            T[] t = array;
    
            return t == array && t != null;
        }
    }
    

    您可以这样验证:

    public static void main(String[] args) {
        TestClass<Byte> test = new TestClass<Byte>(Byte.class);
        // No ClassCastException here
        Byte[] array = test.getArray();
        System.out.println(Arrays.asList(array));
    }
    

    由于类型擦除,如果不使用 Class&lt;?&gt; 对象作为构造函数参数,您将无法解决此问题。

    【讨论】:

    • 但是修复类会破坏方法的通用性,不是吗?这样一来,每种类型都有ClassCastException,但Byte
    • OP 的TestClass 中没有通用方法。 TestClass 本身就是通用的……
    • 这是我想去的地方(编辑 Q 以希望更好地反映这一点)。我在一个通用数组之后,遇到了新的 Object[x] 方法和 Array.newInstance() 方法。看到没有传递 Class 对象就无法使用 Array.newInstance() 令人失望。
    • @SimonCampbell:不,没有。 Java 数组使用协方差。如果你想要一个T[] 数组,你需要以Class&lt;T&gt; 的形式提供T 的类型。由于&lt;T&gt; 本身已被删除,因此泛型信息在运行时不再可用。 Boris mentioned a trick,在某些特殊情况下有效。在这种情况下,它不起作用......
    【解决方案2】:
    array = (T[]) new TestClass[32];
    

    在我看来,这不像 Byte[],编译器应该警告你泛型转换在运行时被忽略。

    这是通用解决方案

    TestClass(Class<T> tclass){
       //create an array for the generic type
       array = (T[])java.lang.reflect.Array.newInstance(tclass,32);
    }
    
    
    TestClass<Byte> bTest = new TestClass(Byte.class);
    

    【讨论】:

      【解决方案3】:

      有一种方法可以找出通用类型类的实际类型参数。

      我刚刚为 Main 类更改了这样的构造函数。

      public class TestClass<T> {
      T[] array;
      
      @SuppressWarnings("unchecked")
      public TestClass() {
          Class<T> objClass;
          objClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; // Found the type paramenter
          array = (T[]) Array.newInstance( objClass, 32);
      }
      
      public T[] getArray() {
          return array;
      }
      
      public boolean doThing() {
          T[] t = array;
      
          return t == array && t != null;
      } }
      

      还有测试方法..

      @Test
      public void test() {
          TestClass<Byte> t = new TestClass<Byte>(){}; // Added {}
          Byte[] b = t.getArray(); 
      
          Assert.assertTrue(t.doThing()); 
          Assert.assertTrue(b.length != 0);
      }
      

      【讨论】:

      • 我刚刚将一个类类型参数传递给构造函数。
      • 有趣...但是,您需要每个&lt;T&gt; 类型的子类,如果子类是匿名的,甚至可能每个实例...而且您永远不能忘记子类TestClass...也许使TestClassabstract?
      • 完全正确.. 使其成为抽象类可以避免在编译时出现问题。但这取决于课程的作者和他的要求..是使其抽象还是只传递一个类类型..
      【解决方案4】:

      这一行是错误的:

      public TestClass() {
          array = (T[]) new TestClass[32];
      }
      

      这与您的问题的标题相矛盾,即“T 是字节”,因为 T 被初始化为 TestClass。

      一个想法是将数组更改为 List

      【讨论】:

      • new T[] 在java中不起作用,泛型类型在运行时不存在。
      • @josefx 是的,我很抱歉。更新答案
      猜你喜欢
      • 1970-01-01
      • 2022-01-15
      • 2013-03-08
      • 1970-01-01
      • 2012-10-23
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多