После этой строки:
qty = scan.nextInt();
Всегда добавляйте еще одну строку для очистки сканера:
scan.nextLine();
Кроме того, используйте
sc.nextLine();
вместо
sc.next();
Вы пытаетесь выполнить invokespecial
на экземпляре Type
(возвращаемом invokevirtual
@ 9), в то время как верификатор ожидает ссылку на текущий класс, т.е. Type$ClassType
.
См. JVMS §4.10.1.9 :
Можно корректно заменить типы, соответствующие текущему классу , и типы аргументов, приведенные в дескрипторе для входящего стек операндов с возвращаемым типом, заданным в дескрипторе, с выходным состоянием типа.
BLOCKQUOTE>
invokespecial
используется для реализации любой из трех вещей
private
super. …
Хотя 1. здесь не применяется (поскольку имя целевого метода не <init>
), в любом из других случаев требуется, чтобы тип получателя был текущего класса или его подкласса. Таким образом, даже когда класс объявления метода равен Type
, ожидается, что фактический тип получателя будет назначаться текущему классу, Type$ClassType
.
Ближайшим эквивалентом того, что вы создали со своим изменением, является вызов super
, хотя в исходном коде Java вызов метода через super
заставляет ссылку на приемник быть такой же, как this
, что присваивается текущему классу.
На уровне байт-кода правила менее ограничительны, тем не менее, вызов метода, позволяющий обходить объявления методов в вашем текущем классе или его подклассах, не разрешается вызывать для ссылки на тип, которая может указывать на экземпляр полностью несвязанная иерархия подклассов, то есть Type
не является Type$ClassType
.
Соответствующее правило JVMS уже упоминалось в ответе Апангина .