Создайте не-generic интерфейс IProcessor с методами process и display, реализуйте его уже в generic классе Processor...
Я по-началу тоже думал в этом направлении. Ещё не пробовал реализовывать, но исключительно ради методических соображений надо таки реализовать и так. Я просто думаю (...пока ещё), что раз можно переменной-типа-интерфейс присваивать значения переменных-типа-классов-реализующих-этот-интерфейс, то почему-бы нельзя нечто подобное сделать и для обобщённых типов? Всё та же концепция наследования в ООП.
А в Processor везде заменить T на MyInterface...
Так делать нельзя! Вернее, сделать то можно, вот только цена за это будет велика: решение о том, какой метод (читай: код программы) выполнять будет приниматься не на этапе компиляции, а на этапе выполнения программы по таблице с помощью динамического поиска методов. Это негативно скажется на производительности, даже если CPU быстро обучится и будет правильно предсказывать переходы. Зачем плодить лишний код, когда без него можно обойтись?
...(сам Processor вряд ли должен реализовывать MyInterface).
В коде выше в объявлении класса
Processor интерфейс
MyInterface указан по отношению к обобщённому типу
T, а не к самому классу. Это нужно, чтобы компилятор знал, какие методы обобщённого типа можно использовать для работы с ним в теле методов класса
Processor. При этом выбор методов происходит на этапе
компиляции, а не выполнения.
Еще я сомневаюсь, что MyInterface должен быть шаблонным. Вроде бы можно объявить его как...
Вместо объяснения контраргумент: интерфейс
Comparable не случайно сделали шаблонным.
А еще вам кажется не нужно поле result в MyClassA - этот массив можно спокойно создать прямо в MyClassA::expand.
Результат работы функции
expand () — это массив, длина которого заранее не известна. Поэтому его придётся создавать с запасом, а потом урезать (при необходимости). В результате, при каждом вызове этой функции в памяти в будет создаваться до двух копий массива (с запасом и урезанный), которые после их обработки будут сразу выкидываться и отправляться в коллектор мусора. Это не рационально. Когда внутри класса имеется статический массив с запасом, создаваться и затем отправляться в мусор будет только один массив на вызов функции
expand () — тот, который она возвращает.
Более грамотной реализацией будет, пожалуй, передавать в функцию
expand () какой-нибудь
ArrayList <MyClassA>, который она будет заполнять. Эта коллекция будет создаваться лишь один раз в классе
Processor, поэтому никаких дополнительных расходов динамической памяти на возвращение результата работы функции не будет.
-- 13.07.2021, 20:38 --ЭВРИКА! Нашёл решение, ключевое слово для Гугла:
Wildcard (в коде программы так называется знак вопроса). Там ещё вдогонку идут ключевые слова
extends и
super, с которыми мне ещё разбираться и разбираться. И вообще, походу, код выше необходимо подвергнуть концептуальной чистке, чего я пока сделать не могу за отсутствием понимания. Но следующий код работает сходу:
public class Test_Interface_Usage {
public static void main (String [] args) {
Processor <?> proc;
proc = new Processor <> (new MyClassA (1, 3));
proc .process (200);
proc .display ();
System .out .println ();
proc = new Processor <> (new MyClassB (1, 3));
proc .process (200);
proc .display ();
}
}