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

Мне нужно передать класс универсального типа в конструктор класса. Класс 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 ответа

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

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

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

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

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.