Kaip gauti bendro tipo T klasės egzempliorių

Turiu bendrąją klasę, Foo<T> . Foo metodu noriu gauti T tipo klasės egzempliorių, bet tiesiog negaliu skambinti T.class .

Koks yra pageidaujamas būdas apeiti jį su T.class ?

462
09 авг. nustatė robinmag 09 rug . 2010-08-09 09:58 '10, 9:58 val. 2010-08-09 09:58
@ 16 atsakymų

Trumpas atsakymas yra tas, kad „Java“ negali žinoti bendrų tipų parametrų vykdymo metu. Jei norite sužinoti daugiau, skaitykite „ Java“ vadovo skyrių apie stilių ištrynimą.

Tai populiarus sprendimas, pavyzdžiui, perduoti Class tipo parametrą bendrinio tipo konstruktoriui.

 class Foo<T> { final Class<T> typeParameterClass; public Foo(Class<T> typeParameterClass) { this.typeParameterClass = typeParameterClass; } public void bar() { // you can access the typeParameterClass here and do whatever you like } } 
383
09 авг. Atsakymas suteiktas Zsolt Török 09 rug. 2010-08-09 10:03 '10, 10:03, 2010-08-09 10:03

Aš ieškojau būdų, kaip tai padaryti, nepridėdamas papildomų priklausomybių klasėje. Po tam tikro tyrimo, aš sužinojau, kad jis įmanoma, jei turite bendrinį tipą. Tai man buvo normalu, nes dirbau su DAO su universaliu super tipo lygmeniu. Jei tai atitinka jūsų scenarijų, tai yra švariausias požiūris IMHO.

Dauguma generinių vaistų vartoja atvejus, su kuriais susidūriau, pvz., Tam tikra bendro pobūdžio. GenericDAO<T> List<T>ArrayList<T> arba GenericDAO<T> DAO<T> ir kt.

Išvalykite „Java“ sprendimą

Prieiga prie bendrųjų tipų vykdymo metu „Java“ paaiškina, kaip galite tai padaryti naudojant „Java“.

Pavasario sprendimas

Pavasaris buvo naudojamas mano projekte, kuris yra dar geresnis, nes pavasarį turi patogų metodą ieškant tipo. Tai geriausias būdas man, nes jis atrodo tvarkingas. Manau, jei nenaudojote pavasario, galite parašyti savo naudingumo metodą.

 import org.springframework.core.GenericTypeResolver; public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T> { @Autowired private SessionFactory sessionFactory; private final Class<T> genericType; private final String RECORD_COUNT_HQL; private final String FIND_ALL_HQL; @SuppressWarnings("unchecked") public AbstractHibernateDao() { this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class); this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName(); this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t "; } 
161
09 февр. Ben Thurley atsakymas 09 vasaris 2012-02-09 01:14 '12 at 1:14 2012-02-09 01:14

Tačiau yra nedidelė spraga: jei apibrėžiate Foo klasę kaip abstrakčią. Tai reikštų, kad turite sukurti klasės egzempliorių:

 Foo<MyType> myFoo = new Foo<MyType>(){}; 

(Atkreipkite dėmesį į dvigubas petnešos pabaigoje.)

Dabar galite gauti T tipą vykdymo metu:

 Type mySuperclass = myFoo.getClass().getGenericSuperclass(); Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0]; 

Atkreipkite dėmesį, kad „ mySuperclass turi būti klasės klasės superklasė, kuri faktiškai apibrėžia galutinį T tipą.

Jis taip pat nėra labai elegantiškas, tačiau turite nuspręsti, ar pageidaujate new Foo<MyType>(){} ar new Foo<MyType>(MyType.class); kodą.


Pavyzdžiui:

 import java.> 

Tada:

 public class Main { // Note the braces... private Deque<String> stack = new SilentStack<String>(){}; public static void main( String args[] ) { // Returns a new instance of String. String s = stack.pop(); System.out.printf( "s = '%s'\n", s ); } } 
73
16 апр. atsakymas bert bruynooghe balandžio 16 d 2011-04-16 08:51 '11 at 8:51 2011-04-16 08:51

Standartinis metodas / problemos sprendimas / sprendimas yra pridėti class objektą konstruktoriui (-ams), pavyzdžiui:

  public class Foo<T> { private Class<T> type; public Foo(Class<T> type) { this.type = type; } public Class<T> getType() { return type; } public T newInstance() { return type.newInstance(); } } 
30
09 авг. atsakymą pateikė Andreas_D 09 rug. 2010-08-09 10:07 '10, 10:07 val. 2010-08-09 10:07

Įsivaizduokite, kad turite abstrakčią klasę, kuri yra bendra:

 public abstract class Foo<? extends T> {} 

Ir tada jūs turite antrą klasę, kuri išplečia „Foo“ su bendrosios juostos pagalba, kuri apima T:

 public class Second extends Foo<Bar> {} 

Bar.class klasę galite gauti „Foo“ klasėje, pasirinkdami „ Type (iš „bert bruynooghe“ atsakymo) ir skambindami naudodami Class pavyzdį:

 Type mySuperclass = myFoo.getClass().getGenericSuperclass(); Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0]; //Parse it as String String className = tType.toString().split(" ")[1]; Class clazz = Class.forName(className); 

Turėtumėte atkreipti dėmesį, kad ši operacija nėra ideali, todėl rekomenduojama išsaugoti apskaičiuotą vertę, kad būtų išvengta daugelio skaičiavimų. Vienas iš tipinių naudojimo būdų yra bendras DAO įgyvendinimas.

Galutinis įgyvendinimas:

 public abstract class Foo<T> { private Class<T> inferedClass; public Class<T> getGenericClass(){ if(inferedClass == null){ Type mySuperclass = getClass().getGenericSuperclass(); Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0]; String className = tType.toString().split(" ")[1]; inferedClass = Class.forName(className); } return inferedClass; } } 

Grąžinimo reikšmė yra Bar.class, kai skambinama iš Foo klasės kitoje funkcijoje arba iš Bar klasės.

16
27 марта '14 в 2:20 2014-03-27 02:20 atsakymas droidpl kovo 27 d. 14:20 2014-03-27 02:20

Čia yra darbo sprendimas !!!

 @SuppressWarnings("unchecked") private Class<T> getGenericTypeClass() {try {String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();Class<?> clazz = Class.forName(className);return (Class<T>) clazz;} catch (Exception e) {throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");} } 

PASTABOS: Galima naudoti tik kaip superklasė.
1. Turi būti pratęstas naudojant įvestą klasę ( Child extends Generic<Integer> )
Or
2. Turi būti sukurtas kaip anoniminis įgyvendinimas ( new Generic<Integer>() {}; )

11
30 нояб. Atsakymą pateikė Jaroslavas Kovbasas, lapkričio 30 d 2015-11-30 14:09 '15 - 14:09 2015-11-30 14:09

Jūs negalite to padaryti dėl ištrinimo stilių. Taip pat žr. „ Java“ generinių stekų perpildymo - tipo trinties klausimą - kada ir kas vyksta .

8
09 авг. atsakymas pateikiamas Konrad Garus 09 rug . 2010-08-09 10:02 '10, 10:02, 2010-08-09 10:02

Geresnis maršrutas, nei kitoms siūloma klasė, yra perduoti objektą, kuris gali padaryti tai, ką darytumėte su klase, pavyzdžiui, sukurkite naują instanciją.

 interface Factory<T> { T apply(); } <T> void List<T> make10(Factory<T> factory) { List<T> result = new ArrayList<T>(); for (int a = 0; a < 10; a++) result.add(factory.apply()); return result; } class FooFactory<T> implements Factory<Foo<T>> { public Foo<T> apply() { return new Foo<T>(); } } List<Foo<Integer>> foos = make10(new FooFactory<Integer>()); 
6
09 авг. Ricky Clarkson atsakymas 09 rug. 2010-08-09 14:47 '10, 14:47 PM 2010-08-09 14:47

Turėjau šią problemą abstrakčioje bendrojoje klasėje. Šiuo konkrečiu atveju sprendimas yra paprastesnis:

 abstract class Foo<T> { abstract Class<T> getTClass(); //... } 

ir tada gauta klasė:

 class Bar extends Foo<Whatever> { @Override Class<T> getTClass() { return Whatever.class; } } 
6
21 окт. atsakymas, kurį pateikė user1154664 Oct 21. 2012-10-21 05:41 '12 at 5:41 am 2012-10-21 05:41

Tai įmanoma:

 class Foo<T> { Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0); } 

Jums reikia dviejų funkcijų iš svn / trunk / dao / src / main / java / com / googlecode / genericdao / dao / DAOUtil.java .

Norėdami gauti daugiau informacijos, žr.

4
18 янв. Peter Tseng atsakymas, pateiktas sausio 18 d 2013-01-18 00:22 '13 - 0:22 2013-01-18 00:22
  public <T> T yourMethodSignature(Class<T> type) { // get some object and check the type match the given type Object result = ... if (type.isAssignableFrom(result.getClass())) { return (T)result; } else { // handle the error } } 
1
02 апр. atsakymą pateikė Abel ANEIROS 02 Bal. 2014-04-02 15:45 '14, 15:45, 2014-04-02 15:45

Jei išplėsite arba diegiate klasę / sąsają, kuri naudoja bendrus elementus, galite gauti bendrojo tipo tėvų klasę / sąsają nekeičiant jokių esamų klasių / sąsajų.

Galimos trys galimybės:

1 atvejis Kai jūsų klasė praplečia klasę, kurią naudoja Generics

 public class TestGenerics { public static void main(String[] args) { Type type = TestMySuperGenericType.class.getGenericSuperclass(); Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments(); for(Type gType : gTypes){ System.out.println("Generic type:"+gType.toString()); } } } class GenericClass<T> { public void print(T obj){}; } class TestMySuperGenericType extends GenericClass<Integer> { } 

2 atvejis Kai jūsų klasė įgyvendina „Generics“ naudojamą sąsają

 public class TestGenerics { public static void main(String[] args) { Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces(); for(Type type : interfaces){ Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments(); for(Type gType : gTypes){ System.out.println("Generic type:"+gType.toString()); } } } } interface GenericClass<T> { public void print(T obj); } class TestMySuperGenericType implements GenericClass<Integer> { public void print(Integer obj){} } 

3 atvejis Kai sąsaja praplečia „Generics“ naudojamą sąsają

 public class TestGenerics { public static void main(String[] args) { Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces(); for(Type type : interfaces){ Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments(); for(Type gType : gTypes){ System.out.println("Generic type:"+gType.toString()); } } } } interface GenericClass<T> { public void print(T obj); } interface TestMySuperGenericType extends GenericClass<Integer> { } 
1
05 дек. atsakymą pateikė Anil Agrawal 05 dec. 2016-12-05 13:43 '16 at 13:43 pm 2016-12-05 13:43

Turiu (bjaurų, bet veiksmingą) šios problemos sprendimą, kurį neseniai naudoju:

 import java.> 
0
07 нояб. atsakymas pateikiamas Unknown6656 07 Nov. 2017-11-07 09:20 '17 at 9:20 2017-11-07 09:20

Kaip paaiškinta kituose atsakymuose, norėdami naudoti šį „ ParameterizedType metodą, jums reikia išplėsti klasę, tačiau tai atrodo kaip papildomas darbas, kad padarytumėte visiškai naują klasę, kuri ją išplėsta ...

Taigi, sudarant abstrakčią klasę, ji verčia jus ją išplėsti, taip tenkindama poklasio reikalavimą. (naudojant lombok @Getter).

 @Getter public abstract class ConfigurationDefinition<T> { private Class<T> type; ... public ConfigurationDefinition(...) { this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; ... } } 

Dabar norėdami ją išplėsti nenustatydami naujos klasės. (Atkreipkite dėmesį, kad {} pabaigoje ... plečiamas, bet neperrašomas nieko - jei nenorite).

 private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){}; private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){}; ... Class stringType = myConfigA.getType(); Class fileType = myConfigB.getType(); 
0
20 сент. atsakymą pateikė Riaan Schutte 20 sep . 2017-09-20 05:44 '17, 5:44 2017-09-20 05:44

Tiesą sakant, manau, kad jūs turite lauką savo T klasės klasei. Jei nėra T tipo lauko, tada kuris taškas turi bendrą tipą? Taigi, jūs galite tai padaryti tik šioje srityje.

Mano atveju, turiu

  <T> elementų sąrašas; 
mano klasėje, ir aš patikrinu, ar klasės tipas yra „Vietovė“
  jei (items.get (0) instancija vietoje) ...

Žinoma, tai veikia tik tuo atveju, jei bendras galimų klasių skaičius yra ribotas.

0
11 нояб. Atsakymą pateikė Christine lapkričio 11 d. 2011-11-11 14:51 '11 at 14:51 2011-11-11 14:51

Tam naudoju problemą:

 class MyClass extends Foo<T> { .... } MyClass myClassInstance = MyClass.class.newInstance(); 
-2
27 июня '17 в 11:45 2017-06-27 11:45 atsakymas pateikiamas nikolai.serdiuk birželio 27 d. 17 val. 11:45 2017-06-27 11:45

Kiti klausimai apie „ žymų arba „ Klauskite“