Ayant appris pendant mes jours C ++ sur les maux de l'opérateur de cast de style C, j'ai d'abord été heureux de constater que Java 5 java.lang.Class
avait acquis une cast
méthode.
Je pensais que finalement nous avions une façon OO de gérer le casting.
Il s'avère que ce Class.cast
n'est pas la même chose qu'en static_cast
C ++. C'est plus comme reinterpret_cast
. Il ne générera pas une erreur de compilation là où elle est attendue et se reportera à l'exécution. Voici un cas de test simple pour démontrer différents comportements.
package test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class TestCast
{
static final class Foo
{
}
static class Bar
{
}
static final class BarSubclass
extends Bar
{
}
@Test
public void test ( )
{
final Foo foo = new Foo( );
final Bar bar = new Bar( );
final BarSubclass bar_subclass = new BarSubclass( );
{
final Bar bar_ref = bar;
}
{
// Compilation error
final Bar bar_ref = foo;
}
{
// Compilation error
final Bar bar_ref = (Bar) foo;
}
try
{
// !!! Compiles fine, runtime exception
Bar.class.cast( foo );
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
{
final Bar bar_ref = bar_subclass;
}
try
{
// Compiles fine, runtime exception, equivalent of C++ dynamic_cast
final BarSubclass bar_subclass_ref = (BarSubclass) bar;
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
}
}
Alors, ce sont mes questions.
- Devrait
Class.cast()
être banni sur le territoire des génériques? Là, il a plusieurs utilisations légitimes. - Les compilateurs doivent-ils générer des erreurs de compilation quand
Class.cast()
est utilisé et que des conditions illégales peuvent être déterminées au moment de la compilation? - Java devrait-il fournir un opérateur de cast comme une construction de langage similaire à C ++?
java
generics
casting
compiler-warnings
Alexander Pogrebnyak
la source
la source
Class.cast()
lorsque des conditions illégales peuvent être déterminées au moment de la compilation. Dans ce cas, tout le monde sauf vous utilise simplement l'opérateur de distribution standard. (3) Java a un opérateur de cast comme construction de langage. Ce n'est pas similaire au C ++. En effet, de nombreuses constructions de langage Java ne sont pas similaires à C ++. Malgré les similitudes superficielles, Java et C ++ sont assez différents.Réponses:
Je n'ai jamais utilisé
Class.cast(Object)
pour éviter les avertissements dans le "pays des génériques". Je vois souvent des méthodes faire des choses comme ceci:Il est souvent préférable de le remplacer par:
C'est le seul cas d'utilisation que
Class.cast(Object)
je connaisse.Concernant les avertissements du compilateur: je suppose que ce
Class.cast(Object)
n'est pas spécial pour le compilateur. Il pourrait être optimisé lorsqu'il est utilisé de manière statique (c'est-à-direFoo.class.cast(o)
plutôt quecls.cast(o)
) mais je n'ai jamais vu personne l'utiliser - ce qui rend l'effort de construire cette optimisation dans le compilateur quelque peu inutile.la source
Tout d'abord, vous êtes fortement déconseillé de faire presque n'importe quel casting, vous devriez donc le limiter autant que possible! Vous perdez les avantages des fonctionnalités fortement typées de Java au moment de la compilation.
Dans tous les cas,
Class.cast()
doit être utilisé principalement lorsque vous récupérez leClass
jeton par réflexion. C'est plus idiomatique d'écrireplutôt que
EDIT: Erreurs au moment de la compilation
Dans l'ensemble, Java n'effectue des vérifications de cast qu'au moment de l'exécution. Cependant, le compilateur peut émettre une erreur s'il peut prouver que de tels transtypages ne peuvent jamais réussir (par exemple, transtyper une classe en une autre classe qui n'est pas un supertype et convertir un type de classe final en classe / interface qui n'est pas dans sa hiérarchie de types). Ici, puisque
Foo
et qu'ilBar
y a des classes qui ne sont pas dans une autre hiérarchie, le casting ne peut jamais réussir.la source
Class.cast
semblent correspondre à la facture, cela crée plus de problèmes que cela n'en résout.Il est toujours problématique et souvent trompeur d'essayer de traduire des constructions et des concepts entre les langues. Le casting ne fait pas exception. Surtout parce que Java est un langage dynamique et que C ++ est quelque peu différent.
Tout le casting en Java, peu importe comment vous le faites, est effectué au moment de l'exécution. Les informations de type sont conservées lors de l'exécution. C ++ est un peu plus un mélange. Vous pouvez convertir une structure en C ++ en une autre et il s'agit simplement d'une réinterprétation des octets qui représentent ces structures. Java ne fonctionne pas de cette façon.
Les génériques Java et C ++ sont également très différents. Ne vous inquiétez pas trop de la façon dont vous faites les choses C ++ en Java. Vous devez apprendre à faire les choses à la manière Java.
la source
(Bar) foo
cela génère une erreur au moment de la compilation, maisBar.class.cast(foo)
pas. À mon avis, s'il est utilisé de cette manière, il le devrait.Bar.class.cast(foo)
indique explicitement au compilateur que vous souhaitez effectuer le cast au moment de l'exécution. Si vous souhaitez vérifier à la compilation la validité de la distribution, votre seul choix est de faire la(Bar) foo
distribution de style.Class.cast()
est rarement utilisé dans le code Java. S'il est utilisé alors généralement avec des types qui ne sont connus qu'au moment de l'exécution (c'est-à-dire via leursClass
objets respectifs et par un paramètre de type). Il n'est vraiment utile que dans le code qui utilise des génériques (c'est aussi la raison pour laquelle il n'a pas été introduit plus tôt).Ce n'est pas similaire à
reinterpret_cast
, car il ne vous permettra pas de casser le système de types à l'exécution, pas plus qu'un cast normal (c'est-à-dire que vous pouvez casser les paramètres de type générique, mais ne pouvez pas casser les types "réels").Les maux de l'opérateur de conversion de style C ne s'appliquent généralement pas à Java. Le code Java qui ressemble à un cast de style C est le plus similaire à un
dynamic_cast<>()
avec un type de référence en Java (rappelez-vous: Java a des informations de type d'exécution).En général, la comparaison des opérateurs de conversion C ++ avec la conversion Java est assez difficile car en Java, vous ne pouvez convertir que des références et aucune conversion ne se produit aux objets (seules les valeurs primitives peuvent être converties à l'aide de cette syntaxe).
la source
dynamic_cast<>()
avec un type de référence.En général, l'opérateur de conversion est préféré à la méthode de conversion Class # car il est plus concis et peut être analysé par le compilateur pour cracher des problèmes flagrants avec le code.
La classe # cast prend la responsabilité de la vérification de type au moment de l'exécution plutôt que pendant la compilation.
Il y a certainement des cas d'utilisation pour Class # cast, en particulier lorsqu'il s'agit d'opérations réfléchissantes.
Depuis que lambda est arrivé à Java, j'aime personnellement utiliser Class # cast avec l'API collections / stream si je travaille avec des types abstraits, par exemple.
la source
C ++ et Java sont des langages différents.
L'opérateur de conversion de style Java C est beaucoup plus restreint que la version C / C ++. En fait, le cast Java est comme le dynamic_cast C ++ si l'objet que vous avez ne peut pas être converti dans la nouvelle classe, vous obtiendrez une exception à l'exécution (ou s'il y a suffisamment d'informations dans le code à la compilation). Ainsi, l'idée C ++ de ne pas utiliser de casts de type C n'est pas une bonne idée en Java
la source
En plus de supprimer les avertissements de cast laids comme la plupart mentionnés, Class.cast est principalement utilisé avec le casting générique, car les informations génériques seront effacées au moment de l'exécution et comment chaque générique sera considéré comme Object, cela conduit à ne pas lancer une exception ClassCastException.
par exemple serviceLoder utilisez cette astuce lors de la création des objets, vérifiez S p = service.cast (c.newInstance ()); cela lèvera une exception de conversion de classe lorsque SP = (S) c.newInstance (); ne sera pas et peut afficher un avertissement `` Sécurité de type: transtypage non coché d'Objet en S '' .
-simplement, il vérifie que l'objet casté est une instance de la classe de conversion puis il utilisera l'opérateur de conversion pour convertir et masquer l'avertissement en le supprimant.
implémentation java pour la diffusion dynamique:
la source
Personnellement, je l'ai déjà utilisé pour créer un convertisseur JSON en POJO. Dans le cas où le JSONObject traité avec la fonction contient un tableau ou des JSONObjects imbriqués (ce qui implique que les données ici ne sont pas de type primitif ou
String
), j'essaie d'appeler la méthode setter en utilisantclass.cast()
de cette manière:Je ne sais pas si cela est extrêmement utile, mais comme nous l'avons déjà dit, la réflexion est l'un des très rares cas d'utilisation légitimes auxquels
class.cast()
je puisse penser, au moins vous avez un autre exemple maintenant.la source