2010-01-10 10 views
3

Comment écrire une méthode générique en Java.Comment écrire une méthode générique en Java

En C# Je ferais ce

public static T Resolve<T>() 
    { 
     return (T) new object(); 
    } 

Ce qui est l'équivalent en Java?

+5

Votre code C# lève une InvalidCastException si 'T' n'est pas' object'. – dtb

+0

votre méthode générique C# n'est pas un bon exemple puisque pour presque n'importe quelle valeur de T que la distribution lancera. –

Répondre

11

Tout d'abord, votre exemple C# est faux; il va lancer un InvalidCastException sauf si typeof(T) == typeof(object). Vous pouvez y remédier en ajoutant un constraint:

public static T Resolve<T>() where T : new() { 
    return new T(); 
} 

Maintenant, ce serait la syntaxe équivalente en Java (ou, au moins, aussi près que nous pouvons obtenir):

public static <T> T Resolve() { 
    return (T) new T(); 
} 

avis double mention de T dans la déclaration: l'un est le T dans <T> qui paramètre la méthode, et le second est le type de retour T.

Malheureusement, ce qui précède ne fonctionne pas en Java. En raison de la façon dont les génériques Java sont implémentés, les informations sur le type d'exécution à propos de T ne sont pas disponibles. Par conséquent, l'erreur ci-dessus provoque une erreur de compilation. Maintenant, vous pouvez contourner cette contrainte comme ceci:

public static <T> T Resolve(Class<T> c) { 
    return c.newInstance(); 
} 

Notez la nécessité de passer T.class. Ceci est connu comme runtime type token. C'est la manière idiomatique de gérer cette situation.

+0

Cela va jeter quelques exceptions! N'utilisez pas de réflexion dans ces cas. –

+0

@tackline: Non, c'est Java idiomatique pour gérer cette situation: cf. http://java.sun.com/docs/books/tutorial/extra/generics/literals.html – jason

+0

"Tout d'abord, votre exemple C# est faux". Je ne pense pas que ce soit une erreur pour une méthode de lancer une exception dans certaines situations (exemple d'OP) (surtout dans une question sur la syntaxe). Je pense cependant qu'il est faux pour une méthode de ne pas compiler (votre exemple C#). Vous avez oublié le '' après 'Resolve'. –

1

Essayez cette http://java.sun.com/docs/books/tutorial/extra/generics/methods.html

public static <T> T Resolve() 
    { 
     return (T) new Object(); 
    } 

Soyez prudent (T) mais je ne suis pas sûr que ce soit correct. Je sais que la distribution générique pose beaucoup de problèmes. Je l'ai déjà passé beaucoup de temps ...

+2

Ce code ne lancerait-il pas 'java.lang.ClassCastException'? – missingfaktor

+0

Cela fonctionne bien dans Java car T est effacé à l'objet lors de la compilation. Cependant, vous n'obtenez vraiment aucune sécurité de type dans cette implémentation. –

+0

@ GreyMatter 9: à droite, la méthode Resolve provoque une exception java.lang.ClassCastException si T est un autre type que java.lang.Object. –

2

Comme d'autres commentateurs l'ont souligné, vous pouvez le faire avec Java ainsi - avec autant d'une possibilité de créer une exception coulée lors de l'exécution:

@SuppressWarnings("unchecked") 
public static <T> T resolve() { 
    return (T) new Object(); 
} 

Sauf si vous utilisez l'annotation @SuppressWarnings, cependant, L'effacement de type de Java entre en jeu et vous obtiendrez un avertissement de compilateur. L'exception se produira également ailleurs: où que vous essayiez de l'utiliser:

String s = <String>resolve(); 

lèvera l'exception. Par contre, vous vouliez probablement utiliser new T() en C# de toute façon. C'est impossible à faire en Java. La solution de contournement suggérée consiste à utiliser Class<T> en tant que paramètre de type si vous devez vous fier aux informations de type lors de l'exécution.Pour exemple, cela signifie que vous devez refactoriser à cette version:

public static <T> T resolve(Class<T> type) { 
    try { 
    return type.newInstance(); 
    } catch(Exception e) { 
    // deal with the exceptions that can happen if 
    // the type doesn't have a public default constructor 
    // (something you could write as where T : new() in C#) 
    } 
} 

Par ailleurs, vous pouvez utiliser aussi pour se débarrasser de l'avertissement dans le cas précédent et de placer l'exception d'exécution à une ligne plus sensible:

public static <T> T resolve(Class<T> type) { 
    return type.cast(new Object()); 
} 

Ce morceau de code se comportera exactement comme celui que vous avez donné à titre d'exemple - y compris une exception qui se produit lorsque T est tout type différent de Object.

0

Vous voulez une sorte d'usine:

public interface MyFactory<T> { 
    T newInstance(); 
} 

Ensuite, qui peut être passé dans où il est nécessaire. Dans votre code:

public static T resolve<T>(MyFactory<T> factory) { 
    return factory.newInstance(); 
} 

Remarque: Il n'y a absolument aucune raison d'utiliser la réflexion pour cela !!

+0

Comment newInstance est-il écrit dans MyFactory . Sûrement cela doit utiliser la réflexion pour créer la nouvelle instance? (Désolé, passage de C# à Java encore). – Lisa

+0

Grattez cette question. Je vois que le type de classe java (java.lang.Class) a une méthode newInstance() pour générer une nouvelle instance où il y a un constructeur sans paramètre. – Lisa

+0

@Lisa Vous ne voulez vraiment pas toucher à la réflexion si vous pouvez l'aider. Les implémentations de 'MyFactory' peuvent construire un' T' spécifique comme bon leur semble. –

Questions connexes