ВАЖНЫЙ:
код, который у меня сейчас есть, работает в соответствии с моими ожиданиями. Он делает то, что я хочу. Мой вопрос о том, является ли СПОСОБ, которым я заставил его работать, неправильным. Причина, по которой я спрашиваю об этом, заключается в том, что я видел много результатов переполнения стека о необработанных типах и о том, как их НИКОГДА не следует использовать.
Что я делаю и почему я использовал необработанные типы
В настоящее время я динамически создаю конкретный подкласс универсального интерфейса, где интерфейс принимает параметры при создании класса. Когда я создаю экземпляр этого класса и использую его возвращенный объект для вызова различных методов, я использую необработанные типы, потому что он работает для того, что я пытаюсь сделать. Вот пример в моем функционирующем коде, где используются необработанные типы. Этот код находится в порядке сверху вниз, т.е. между блоками кода нет кода.
Загрузка файла свойств
Properties prop = new Properties();
try {
prop.load(ObjectFactory.class.getResourceAsStream("config.properties"));
Это анализатор файлов, который реализует FileParserImplementation
, принимает данные и помещает их в массив. Этот код получает тип класса, а затем динамически создает экземпляр этого типа.
Class<? extends FileParserImplementation> parser = null;
parser = Class.forName(prop.getProperty("FileParserImplementation")).asSubclass(FileParserImplementation.class);
FileParserImplementation ParserInstance = (FileParserImplementation) parser.getDeclaredConstructors()[0].newInstance();
Эти два класса и их экземпляры являются двумя отдельными DataParsers
, реализующими DataParserImplementation
. Они принимают массив Strings
, который дает FileParser
, и создают объекты/манипулируют данными во все, что необходимо. Он выпускает коллекцию этих данных. Зависимость Fileparser
передается через внедрение конструктора. Это можно настроить через файл свойств во время выполнения.
Class<? extends DataParserImplementation> dataset1 = Class.forName(prop.getProperty("DataParserImplementation_1")).asSubclass(DataParserImplementation.class);
Class<? extends DataParserImplementation> dataset2 = Class.forName(prop.getProperty("DataParserImplementation_2")).asSubclass(DataParserImplementation.class);
DataParserImplementation Dataset1Instance = (DataParserImplementation) dataset1.getDeclaredConstructors()[0].newInstance(ParserInstance);
DataParserImplementation Dataset2Instance = (DataParserImplementation) dataset2.getDeclaredConstructors()[0].newInstance(ParserInstance);
Это класс Crossreferencer
, который реализует CrossReferencerImplementation
. Он принимает два набора данных и перекрестно ссылается на них любым способом, который требуется фактическому конкретному отраженному классу. Это также можно настроить во время выполнения. Он выводит карту в этом файле main. Карта служит окончательным набором данных (я могу изменить это позже).
Class<? extends CrossReferenceImplementation> crossreferencer = Class.forName(prop.getProperty("CrossReferenceImplementation")).asSubclass(CrossReferenceImplementation.class);
CrossReferenceImplementation crossReferencerInstance =
(CrossReferenceImplementation) crossreferencer.getDeclaredConstructors()[0].newInstance();
Получение результата Map от вызова метода в нашем отраженном экземпляре. Затем содержимое этой карты распечатывается. в настоящее время кажется, что параметры карты также получены, потому что объекты, находящиеся внутри карты, правильно используют свои методы toString при вызове reflectiveFinalMap.get(key).toString()
. Это заставляет меня поверить, что это работает так, как я задумал.
Map reflectiveFinalMap = (Map)
crossReferencerInstance.CrossReference(Dataset1Instance.Parse(), Dataset2Instance.Parse());
for (Object key:reflectiveFinalMap.keySet()) {
System.out.println(key + " { " +
reflectiveFinalMap.get(key).toString() + " }");
}
return reflectiveFinalMap;
}
//catch block goes here
Обратите внимание, что каждый раз, когда я рефлективно создаю экземпляр класса, реализующего один из моих интерфейсов, я использую этот интерфейс как необработанный тип. Я надеюсь, что отражение затем увидит параметризованный тип этого необработанного типа при создании конкретного подкласса, потому что именно там фактически указаны типы параметров. Смысл в том, чтобы позволить любому классу, реализующему эти интерфейсы, быть универсальным до такой степени, что он может принимать что угодно и возвращать что угодно.
Вещи, которые я старался не использовать в необработанных типах.
Я попытался фактически получить параметризованный тип CrossReferenceImplementation
в отраженном crossreferencer
Class
, который я получаю прямо сейчас, вызывая
Class arrayparametertype = (Class)((ParameterizedType)crossreferencer.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
И затем я попытался передать это arrayparameter
при создании экземпляра crossreferencer
следующим образом:
CrossReferenceImplementation crossReferencer = (CrossReferenceImplementation<<arrayparametertype>>) crossreferencer.getDeclaredConstructors()[0].newInstance();
Это не сработало, поскольку типы переменных параметров, по-видимому, не имеют значения. Я попытался вручную указать конкретный параметр конкретного отраженного класса (я все равно НЕ хочу этого, потому что здесь нарушается вся точка отражения, отделяя классы друг от друга, имея возможность использовать все, что реализует соответствующий интерфейс). Это привело к появлению этого предупреждения, и код фактически не запускал методы, которые он должен был выполнять:
//how the parameters were specified. Messy and breaks the reflection.
CrossReferenceImplementation<Map<String, SalesRep>,Map<String, SalesRep>,Map<String, SalesRep>> crossReferencer = (CrossReferenceImplementation) crossreferencer.getDeclaredConstructors()[0].newInstance();
//where the warning occured
Map reflectiveFinalMap = (Map) crossReferencer.CrossReference(Dataset1.Parse(), Dataset2.Parse());
Предупреждение: «Набор данных1 имеет необработанный тип, поэтому результат анализа стирается». Обратите внимание, что SalesRep
здесь — это объект, в котором данные хранятся в виде полей этого объекта. Этот объект обрабатывается и помещается в различные коллекции. Доступ к нему также осуществляется через отражение во многих методах DataParserImplementation
s.
Аналогичное сообщение об ошибке и проблема возникли при указании типа параметра карты (ОПЯТЬ, я НЕ хочу этого, потому что это делает отражение бессмысленным, я хочу, чтобы результат возврата карты был универсальным и определялся классом реализации).
//where the parameterized type was specified
Map reflectiveFinalMap = (Map<String,SalesRep>) crossReferencer.CrossReference(Dataset1.Parse(), Dataset2.Parse());
При указании фактического параметризованного типа результата карты сообщение об ошибке было: «crossReferencer
имеет необработанный тип, поэтому результат CrossReference
стирается».
Запуск кода действительно подтвердил для меня, что результаты метода .CrossReference
были стерты, в то время как все остальное работало нормально.
Какие интернет-поиски я пробовал, прежде чем спросить здесь
Поэтому я использовал необработанные типы для обеих операций. Как видно из основного кода, все работало нормально. Но я видел так много "Не используйте необработанные типы". Вот почему я спрашиваю: уместно ли это использование необработанных типов? Должен ли я сделать это по-другому, чтобы НЕ нарушать отражение? Это нарушает отражение, потому что ручное указание параметра типа не только не запускает мой код, но также означает, что можно использовать ТОЛЬКО конкретный класс. Я задумался, чтобы можно было использовать все, что реализует универсальный интерфейс. Я не хочу иметь возможность использовать только конкретные конкретные экземпляры. Я пробовал искать переполнение стека для того, что в моем заголовке и других подобных вещах. Я думаю, что это может быть связано со стиранием шрифта, но я, честно говоря, не уверен в этом. Ничто другое на самом деле не решало эту проблему, потому что ничто не говорило о дженериках, параметризованных типах и отражении сразу (суть моей проблемы). Мне сказали, что дженерики и отражение плохо сочетаются друг с другом, но этот код все равно работает и работает так, как я хочу. Это работает хорошо. Я просто хочу убедиться, что я не делаю что-то УЖАСНО неправильное.
Цель.
Чтобы получить представление о моем текущем использовании необработанных типов, чтобы я знал, что делаю это правильно. Под «правильным» я подразумеваю противоположность тому, что я определяю ниже как «неправильный» путь. Пример того, что я ищу «Понимание», это:
Чтобы понять, почему код пуэсдо выглядит следующим образом:
ConcreteClass forname(myPropertiesFileObject.get(ConcreteClassname)) as subClass of (MyGenericInterface);
MyRAWGenericInterfaceType ConcreteClassInstance = (MyRAWGenericInterfaceType) ConcreteClass.newInstance( Insert generic Type constructor arguments here);
RAWCollectionType someCollection = RAWCollectionType concreteClassInstance.CallingAMethod(Insert generic Type method arguments here);
Использует необработанные типы, где RAW
содержится в имени типа интерфейса или коллекции. Это в отличие от того, чтобы делать это каким-то образом, который не использует необработанные типы, но не нарушает точку отражения, чтобы отделить взаимодействия между этими классами. В этом случае указание параметров с помощью жесткого кода «сломит отражение». Кроме того, я хотел бы понять, почему указание параметров (даже если я знаю, что это не то, что я собираюсь делать) для этих типов RAW
в pusedocode выше вызывает ошибки, перечисленные выше в вопросе, а именно, почему результат CallingAMethod
стерт при подаче фактических параметров в RAWCollectionType
, которые возвращает метод? Основная проблема заключается в том, что когда я задаю параметры типа для RAWCollectionType
при его объявлении, он отказывается обновляться тем, что возвращает CallingAMethod
, и я не понимаю, почему. Он принимает возвращаемое значение, но если тело метода CallingAMethod
имеет возвращаемое значение, переданное в качестве аргумента, обновленное внутри метода, а затем возвращенное, возвращаемое значение, которое я получаю, не содержит обновлений. CallingAMethod
в этом примере было бы похоже, если бы у меня был список вроде:
[1,2,3]
и внутри метода у меня было что-то вроде:
foreach(thing in list){
thing += 1
}
а затем я вернул список, возврат, который я получил бы при указании параметров, был бы [1,2,3], а при использовании необработанных типов это было бы [2,3,4], как я и хотел. Я спрашиваю об этом, потому что слышал плохие вещи об использовании необработанных типов.
Кроме того, я хочу убедиться, что мое использование необработанных типов не является ужасно неправильным и что оно работает, потому что оно ДОЛЖНО работать. Может быть, я только что освоился во всей этой штуке с отражением и дженериками и нашел правильное применение необработанным типам, или я мог делать что-то настолько ужасное, что это заслуживает моего ареста. Вот что я намерен выяснить. Чтобы уточнить, под неправильным я имею в виду:
плохой дизайн (следует использовать другой способ рефлексивного вызова моих методов, а также использовать рефлексивные классы, использующие универсальные интерфейсы)
неэффективный дизайн (с точки зрения временной сложности, строки кода или удобства обслуживания)
есть лучший способ, вы даже не должны делать это в первую очередь
Если какая-либо из этих причин или что-то, что я пропустил, всплыло, когда вы читали этот код, СКАЖИТЕ МНЕ. В противном случае, пожалуйста, объясните, почему мое использование необработанных типов действительно и не является нарушением этого вопроса: [ссылка] Что такое необработанный тип и почему мы не должны его использовать?
FieldAccessor<T>
, но для этого вам все равно нужно будет использовать небезопасное приведение. (но вы все равно можете сделать его типобезопасным во время выполнения) - person GotoFinal   schedule 01.08.2018