2012-04-26 5 views
3

У меня есть тест Java JUnit 4 и общий класс, который создает общий массив. Когда я создаю метод для возвращения этого общего массива, я получаю сообщение об ошибке после его возвращения. Он работает, если я возвращаю ArrayList (где T - экземпляр Byte by class) в ArrayList.Возвращение T [] (где T Byte []) Byte []

Почему массив кажется экземпляром и применим (проверен на более сложных классах), но я не могу вернуть ссылку на этот массив?

Ошибка:

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); 
    } 

} 

ответ

5

А «общий» массив может быть построен с помощью отражения:

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<?> объекта в качестве аргумента конструктора.

+0

Но при фиксации класса вы испортите универсальность метода, не так ли?Таким образом, у вас будет 'ClassCastException' для каждого типа, но' Byte' –

+0

В OP TestClass нет никакого общего метода. 'TestClass' сам по себе является общим ... –

+0

Это на пути к тому, куда я хочу идти (отредактировал Q, чтобы, надеюсь, лучше отразить это). Я получаю общий массив и столкнулся с новым методом Object [x] и Array.newInstance(). Неудивительно, что нельзя использовать Array.newInstance(), не передавая объект класса . –

0

Эта линия является неправильным:

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

Это противоречит заголовку вашего вопроса, то есть «где T является байтом», поскольку T инициализируется в TestClass.

Идея состоит в том, чтобы изменить массив в список < T>.

+0

новый Т [] не работает в Java, общий тип не существует во время выполнения. – josefx

+0

@josefx да, мои извинения. Обновление ответа – maksimov

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); 
1

Существует способ, чтобы выяснить фактические аргументы типа для Generic типизированного класса.

Я только что сменил конструктор для этого класса.

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); 
} 
+0

Я просто избежал передачи аргумента типа Class в конструктор. – vinodn

+1

Интересно ... Но тогда вам нужен подкласс для '' типа, потенциально даже для каждого экземпляра, если подклассы анонимны ... И вы никогда не должны забывать подкласс 'TestClass' ... Может быть, сделать' TestClass' 'abstract' ? –

+0

Точно .., делая его абстрактным классом, избегает проблемы прямо во время компиляции. Но это зависит от автора этого класса и его требований .. ли сделать его абстрактным или просто пройти класс типа .. – vinodn

Смежные вопросы