2010-02-10 6 views
18

Quand un objet peut-il être moulé dans un autre objet? L'objet casté doit-il être un sous-type de l'autre objet? J'essaye de comprendre les règles ...Règles Java pour le moulage

Édition: J'ai réalisé que je n'expliquais pas du tout mon problème: fondamentalement, je lance un objet sur un type d'interface. Cependant, au moment de l'exécution, j'obtiens un java.lang.ClassCastException. Que doit-il se passer avec mon objet pour pouvoir le lancer sur cette interface? Est-ce qu'il doit l'implémenter?

Merci

+0

Dans quelle situation avez-vous besoin en fait de jeter explicitement un objet à son type d'interface? – harto

+0

Vous avez une réponse très utile ici. J'aimerais que vous le sélectionniez. – orbfish

Répondre

1

Vous pouvez lancer si le type d'exécution d'un objet est un sous-type de ce que vous essayez de le jeter dans.

EDIT:

Oui, l'objet que vous essayez de lancer devra implémenter l'interface pour que vous puissiez le jeter avec succès.

+0

Vous pensez tout à fait à tort. Ce que vous devriez demander, c'est «dans quelles situations est-il sensé de traiter ce' Foo' comme un 'IBar'? –

+0

que se passe-t-il si l'objet que j'essaie de lancer vers cette interface étend une classe qui implémente l'interface? cela évitera-t-il l'erreur d'exécution? – alan

+0

oh ok..j'ai essayé de reformuler mon commentaire original puisqu'il n'avait pas vraiment de sens au premier essai – alan

27

En Java, il existe deux types de coulée variable de référence:

  • Downcasting: Si vous avez une variable de référence qui fait référence à un objet sous-type , vous pouvez l'assigner à une variable de référence du sous-type. Vous devez faire une distribution explicite pour faire cela, et le résultat est que vous pouvez accéder aux membres du sous-type avec cette nouvelle variable de référence.

  • transtypage ascendant: Vous pouvez assigner une variable référence à une référence de supertype variables explicitement ou implicitement. Il s'agit d'une opération intrinsèquement sûre car l'affectation limite les capacités d'accès de la nouvelle variable .

Oui, vous devez implémenter l'interface directement ou indirectement pour permettre l'attribution de votre classe d'objet référence au type d'interface.

+0

Je ne suis pas sûr si vous avez écrit ceci, copié, ou résumé, mais c'est excellent, m'a fait réaliser ce que j'essayais de cela n'a aucun sens. – orbfish

+0

des exemples auraient été utiles –

+0

Upvoted en raison du texte écrit par l'homme, pas un bavardage 'B étend A'. –

1

Si:

interface MyInterface{} 

class MyClass implements MyInterface{} 

Puis

MyClass m = new MyClass(); 
MyInterface i = (MyInterface)m; 

est possible.

2

Il y a une manière intuitive de penser à ceci - vous ne changez pas un objet avec une distribution, vous faites seulement quelque chose qui serait déjà permis si le type était connu - en d'autres termes, vous pouvez seulement lancer à un type que votre objet est déjà. Il suffit donc de regarder la chaîne d'objets pour voir quels types s'appliquent à votre objet.

Vous pouvez donc convertir vers une interface seulement si elle est définie quelque part plus haut dans la chaîne (par exemple si votre classe parent l'implémente, etc.).Il doit être explicite - à partir de votre question, il semble que vous pensiez que si vous implémentez la méthode "void foo()" alors vous devriez pouvoir lancer vers une interface qui définit la méthode "void foo()" - ceci est parfois décrit comme "duck typing" (si ça fait du charlatan comme un canard, c'est un canard) mais ce n'est pas comme ça que ça marche.

3

Cela fonctionne:

class Foo implements Runnable { 
    public void run() {} 
} 

Foo foo = new Foo(); 
System.out.println((Runnable) foo); 

Mais ce ne sera pas:

class Bar { 
    public void run() {} 
} 

Bar bar = new Bar(); 
System.out.println((Runnable) bar); 

Parce que même si Bar a une méthode run() que pourrait mettre en œuvre Runnable.run(), Bar n'a pas été déclarée à mettre en œuvre Runnable il ne peut pas être casté à Runnable. Java requiert que vous déclariez des interfaces implémentées par nom. Il n'a pas duck typing, contrairement à d'autres langues telles que Python et Go

2

Supposons que nous voulons jeter objet d A,

A a = (C) d;

Donc, 3 règles internes ont été vérifiées par le compilateur et la JVM. Le compilateur vérifie les 2 premières règles au moment de la compilation et JVM vérifie la dernière règle au moment de l'exécution.

Règle 1 (compilation de temps à vérifier):

Type de 'd' et C doit avoir une certaine relation (enfant à l'enfant ou en même temps parent ou d'un parent ) .Si il n'y a relation alors nous obtiendrons une erreur de compilation (types inconvertibles).

Règle 2 (compilation de temps à vérifier):

'C' doit être soit même type ou type dérivé (sous-classe) de 'A' sinon nous aurons une erreur de compilation (incompatible les types).

Règle 3 (Runtime Exception):

type d'objet d'exécution de 'd' doit être identique ou dérivé d'un type de sinon nous aurons une exception d'exécution 'C' (ClassCastException Exception).

Trouvez des exemples ci-dessous pour obtenir plus d'idée,

String s = new String("hello"); StringBuffer sb = (StringBuffer)s; // Compile error : Invertible types because there is no relationship between. 

Object o = new String("hello"); StringBuffer sb = (String)o;  // Compile error : Incompatible types because String is not child class of StringBuffer. 

Object o = new String("hello"); StringBuffer sb = (StringBuffer)o; // Runtime Exception : ClassCastException because 'o' is string type and trying to cast into StingBuffer and there is no relationship between String and StringBuffer.