Java Общая инициализация объекта
Пожалуйста, сначала посмотрите на этот фрагмент:
public MultiThreadManager( Class<T> c) {
T[] allJobs = (T[]) Array.newInstance( c , MAX_THREAD_SIZE ) ;
for ( int i = 0 ; i < MAX_THREAD_SIZE ; i ++ ) {
allJobs[i] = (T) new Object();
service.submit( allJobs[i] );
getWaitingThreads().add( allJobs[i] );
}
}
Вот исключение:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to slave.JobTemplate
Что я пытаюсь сделать:
Конструктор MultiThreadManager должен принимать универсальный тип (скажем, Job.java), который реализует Callable. Создайте массив всех этих общих типов данных ( Job, Java) . Инициализируйте его, чтобы конструктор универсального типа данных ( Job.java) запускался и выполнял их в службе исполнителя.
Пожалуйста, помогите мне определить мою ошибку или предложите лучший способ.
Заранее спасибо
Спасибо вам всем, но все немного сложнее. Вот другая информация:
public class Job extends JobTemplate<String> {...details ...}
public abstract class JobTemplate< T > implements Callable<T> {...details..}
и наконец
MultiThreadManager< Job > threadManager = new MultiThreadManager< Job >( Job.class );
Еще раз спасибо:)
3 ответа
Вам нужно больше размышлений, так же, как вам нужно создать массив:
allJobs[i] = c.newInstance();
и окружить try-catch для всех этих надоедливых проверенных исключений.
Тем не менее, я бы предложил использовать new Callable[]
потому что нет необходимости вдаваться в специфику фактического типа работы. Вам также следует рассмотреть проект, в котором отражение не требуется: вызывающий объект создает экземпляры заданий, а не передает объект класса. Текущее решение страдает от ограничения на тип задания, который должен быть создан только через конструктор по умолчанию.
Когда ты сказал new Object()
, что создает новый объект класса Object. Его динамический тип во время выполнения - Object. Так что актёрский состав T
не будет логически обоснованным, если T
на самом деле Object
,
Что вам нужно сделать, чтобы создать T
это использовать отражение, чтобы вызвать соответствующий конструктор на T
,
Робин и Марко показали источник проблемы, и у меня есть еще одна вещь, которую стоит подчеркнуть, из "Эффективной Явы" Джошуа Блоха:
Пункт 25: Предпочитайте списки массивам
... массивы и дженерики имеют очень разные правила типов. Массивы ковариантны и ограничены; дженерики инвариантны и стерты. Как следствие, массивы обеспечивают безопасность типов во время выполнения, но не обеспечивают безопасность типов во время компиляции и наоборот для обобщенных типов. Вообще говоря, массивы и дженерики плохо сочетаются. Если вы обнаружите, что смешиваете их и получаете ошибки или предупреждения во время компиляции, ваш первый импульс должен состоять в том, чтобы заменить массивы списками.
Объяснение:
Ковариант - означает, например, что Array of Objects является супертипом Array of Integer. Дженерики неизменны, значит, вы не можете List<Integeer>
к List<Object>
Reified - вся информация, которая существует для массивов во время компиляции, также доступна во время выполнения. Обобщения реализуются с помощью стирания, что означает, что их ограничения типов применяются только во время компиляции, а затем стираются (их не существует во время выполнения).
Подводя итог:
Смешивание массивов с обобщениями, скорее всего, вызовет у вас проблемы - старайтесь не смешивать их, используя списки вместо массивов:
public <T> void MultiThreadManager(Class<T> c)
throws IllegalAccessException, InstantiationException {
List<T> allJobs = new ArrayList<T>(MAX_THREAD_SIZE) ;
for (int i = 0; i < MAX_THREAD_SIZE; i++) {
allJobs.add(c.newInstance());
service.submit( allJobs.get(i) );
getWaitingThreads().add( allJobs.get(i));
}
}