Как вызвать метод статического класса для общего объекта?

Мне нужно передать класс универсального типа в конструктор класса. Класс SpiceRequest из RoboSpice Android для ссылки на конструктор.

Кажется странным, что класс требует передачи родового класса в контрструктор, когда к нему можно получить доступ из самого общего типа, в данном случае RESULT.class, но, возможно, я ошибаюсь в этом. Во всяком случае, я не хочу менять код библиотеки, а скорее должен использовать общий тип для родового типа SpiceRequest, Map. Здесь мой код:

SpiceRequest<map<string, ?="" extends="" object="">> request =
 new SpiceRequest<map<string, ?="" extends="" object="">>(???) {
 ...
 };
</map<string,></map<string,>

И подпись конструктора SpiceRequest:

public SpiceRequest(final Class<result> clazz) {
 ...
}
</result>

Для??? Я пробовал Map.class с ошибкой компилятора: The constructor SpiceRequest<map<string,? extends="" object="">>(Class<map>) is undefined.</map></map<string,?>

Map<string, ?="" extends="" object="">.class</string,> дает ошибку: Syntax error on tokens, PrimitiveType expected instead, в частности подчеркивая ? extends Object. Он также дает ту же ошибку, что и Map.class.

И Map.<string, ?="" extends="" object="">class</string,> также дает ту же ошибку компилятора.

Каков правильный способ получить общий класс Class<map<string, ?="" extends="" object="">></map<string,>?

4 ответа

Нет литералов класса для конкретных параметризованных типов или подстановочных параметров. Из Учебник по дженерикам Анжелики Лангер:

Подстановочные параметры, зависящие от шаблонов, теряют свои аргументы типа, когда они переводится в байтовый код в процессе, называемом стиранием типа. Как сторона эффект стирания типа, все экземпляры общей доли типа одно и то же представление времени выполнения, а именно соответствующее тип. Другими словами, параметризованные типы не имеют типа представление их собственных. Следовательно, нет смысла формируя литералы класса, такие как List <!--?-->.class, List <!--? extends Number-->.class и List<long>.class</long>, так как такие объекты Classсуществовать. Только исходный тип List имеет объект Class, который представляет его тип времени выполнения. Он называется List.class.

Нет литералов класса для конкретных параметризованных типов по тем же причинам, которые в двух словах стирают тип.

Для ваших целей вам просто нужно сделать непроверенный бросок литерала класса:

Class<map<string, ?="">> c = (Class<map<string, ?="">>)(Class<!--?-->)Map.class;
</map<string,></map<string,>

Обратите внимание, что двойное нажатие Class <!--?--> необходимо, потому что прямое преобразование из Class в Class<map<string, ?="">></map<string,> является незаконным.


эта проблема на самом деле не связана с самим RoboSpice, а с ограничением синтаксиса Java: нет никакого литтера, который вы можете использовать для получения класса/типа параметризованного родового типа в Java.

Если вы хотите сделать что-то вроде

public class ListTweetRequest extends SpiceRequest<list<tweet>> {
 public ListTweetRequest(Object cacheKey ) {
 super( <here is="" the="" problem="">, cacheKey );
 }
}
</here></list<tweet>

то вы не можете передать класс List<tweet>.class</tweet> родительскому конструктору. Это действительно ограничение Java как generics реализовано с использованием стирания типа, а List<tweet>.class</tweet> не имеет реального смысла в Java.

Лучшая и самая чистая работа - использовать промежуточный тип, например:

public class ListTweet extends List<tweet> {
}
public class ListTweetRequest extends SpiceRequest<listtweet> {
 public ListTweetRequest(Object cacheKey ) {
 super( ListTweet.class, cacheKey );
 }
}
</listtweet></tweet>

Это имеет преимущество, чтобы предоставить вам реальный тип, который вы можете передать конструктору SpiceRequest. Но остерегайтесь обфускации. В тех случаях proguard попытается удалить класс ListTweet, вы должны явно сохранить его из обфускации.


У меня тоже была проблема, и я нашел решение, подобное @Snicolas.

Посмотрите на этот пример модели Robospice-sample-retrofit:

https://github.com/octo-online/RoboSpice-samples/blob/release/robospice-sample-retrofit/src/com/octo/android/robospice/sample/retrofit/network/SampleRetrofitSpiceRequest.java

На самом деле лучше наследовать не из интерфейса raw List, а для любого подкласса, такого как ArrayList и т.д., иначе вам придется реализовать все методы интерфейса.

import java.util.ArrayList;
public class Contributor {
 public String login;
 public int contributions;
 @SuppressWarnings("serial")
 public static class List extends ArrayList<contributor> {
 }
}
</contributor>


Я всегда угадываю стирание, но попробовал ли вы просто называть его Map.class?

licensed under cc by-sa 3.0 with attribution.