Question

En Java, supposons que j'ai 3 classes, C s'étend de B qui s'étend de A.

class X {
   interface A {}
   interface B extends A {}
   interface C extends B {}
   void f(A a) {}

   void test() {
      C c = new C()
      B b = (B) c;

      f(b);
   }
}

Si je fais quelque chose comme ceci, comme indiqué dans test () ci-dessus:

C c = new C()
B b = (B) c;

f(b);

f () accepte b en tant que type C puisque C et B les deux vont de A . Je voulais que f () reçoive b en tant que type B et non en tant que C .

Y a-t-il un moyen de forcer cette surclassement?

Était-ce utile?

La solution

f () recevra toujours quelque chose de type A (même si sous les couvertures, il s’agit en réalité d’un B ou d’un C, et peut être converti de manière appropriée).

Vous pouvez définir un f () supplémentaire, donc

f(B b);

et si nécessaire

f(C c);

et le bon sera appelé en fonction de la classe de l'argument. c'est-à-dire que le compilateur détermine quelle fonction est appelée en fonction du type de l'argument. Cela diffère d’une répartition dynamique (ou polymorphisme) qui se produirait au moment de l’exécution.

Notez que votre distribution dans la question est redondante. Vous pouvez écrire:

C c = new C()
B b = c;

f(b);

puisque C s'étend de B, C est un B.

Autres conseils

Vous semblez confus quant à la différence entre le type de compilation et le type d'exécution.

Vous créez un objet (indiqué par les références c et b) de type C et il restera en C, car il est impossible de modifier le type d'exécution d'un objet et par conséquent son comportement; en diffusant, vous pouvez simplement changer le type de temps de compilation, ce qui affecte la façon dont le compilateur le traite.

Pouvez-vous donner plus d’informations sur le problème concret que vous essayez de résoudre? Il est fort probable qu'il existe un moyen d'atteindre votre objectif en modifiant la conception.

  

Je voulais que f reçoive b comme type B et non pas comme type C.

Un C est un B est un A .

À l'intérieur de f , f ne voit que la partie A de son paramètre a Si f appelle une fonction A publique qui est remplacée par C , la substitution C est appelée.

C'est comme ça que fonctionnent les fonctions virtuelles. L’idée étant que l’objet auquel il est fait référence est vraiment un C , il devrait donc présenter un comportement C . Si vous souhaitez un comportement B , transmettez une instance B , et non une instance C .

Si "C" et "B" doivent avoir le même comportement, ne modifiez pas ce comportement dans C .

Pourquoi voulez-vous faire cela?

Votre question n’a pas de sens. Que voulez-vous dire par "f accepte b comme type C"?

f accepte b comme type A, car la signature de la méthode dit "A". Si vous appelez des méthodes sur b, elles seront invoquées sur C si C les remplace. Mais ceci est un comportement standard en Java (toutes les méthodes sont similaires aux méthodes virtuelles en C ++), et il n’ya aucun moyen de le changer.

Peut-être pouvez-vous décrire votre problème, nous pourrons alors vous aider.

Le fait que vous puissiez passer n'importe quelle sous-classe de A en tant que paramètre de f (A a) est inhérent à OO en Java, vous ne pouvez en aucun cas contourner ce problème. Si C étend A, vous pouvez toujours l’utiliser là où un A. est attendu.

vous pouvez utiliser la réflexion pour vérifier si le paramètre est de classe A:

public void f(A a) {
  if (a.getClass() == A.class) {
    // ok, go on
  }
  else {
    System.err.println("The parameter is not of class A!");
  }
}

Je ne sais pas si c'est ce que vous voulez, mais cela pourrait être utile.

Votre problème peut être résolu en comprenant la différence entre le type REFERENCE et le type INSTANCE. Lorsque vous convertissez votre objet C en B, vous ne changez que le type de référence - l'instance réelle de l'objet est toujours un objet C - cela devrait être assez évident si vous examinez votre objet en mode débogage. La modification du type de référence affecte uniquement la manière dont le compilateur traite / perçoit le code - le comportement de l'exécution ne doit pas être affecté. Tout appel de méthode sur un objet C invoquera toujours la méthode de C (que l'objet ait été ou non transtypé). Si vous surchargez une méthode de B et voulez appeler la version de B de la méthode, vous devez créer une instance de B.

Le fait que votre code ait une référence à un A ne signifie pas que l'objet pointé est également un A. S'il s'agit d'un C, il reste un C. La référence dans votre source limite uniquement les méthodes disponibles dans votre source. Casting n’est nécessaire que parce qu’il faut parfois une méthode sur un type différent et que nous devons tromper le compilateur pour qu’il commence à utiliser des méthodes sur les castes. Naturellement, la conversion peut échouer à l'exécution si la tentative est invalide.

In upcasting and downcasting the  object first upcast then downcastenter
class A
{
}
class B extends A
{
}
Class M
{
  psvm(String ar[])
{

   A a1= new B();
   B b2=(B)a1;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top