web-dev-qa-db-fra.com

Les méthodes substituées peuvent-elles différer en termes de type de retour?

Les méthodes substituées peuvent-elles avoir différents types de retour ?

108
santidoo

Supports Java* types de retour covariants pour les méthodes remplacées. Cela signifie qu'une méthode remplacée peut avoir un type de retour spécifique à plus. Autrement dit, tant que le nouveau type de retour est assignable au type de retour de la méthode que vous substituez, il est autorisé.

Par exemple:

class ShapeBuilder {
    ...
    public Shape build() {
    ....
}

class CircleBuilder extends ShapeBuilder{
    ...
    @Override
    public Circle build() {
    ....
}

Ceci est spécifié dans la section 8.4.5 de la spécification du langage Java :

Les types de retour peuvent varier selon les méthodes qui se substituent si les types de retour sont des types de référence. La notion de substituabilité de type de retour prend en charge les retours covariants, c'est-à-dire la spécialisation du type de retour dans un sous-type.

Une déclaration de méthode d1 avec le type de retour R1 est substituable en type de retour pour une autre méthode d2 avec le type de retour R2, si et seulement si les conditions suivantes sont remplies:

  • Si R1 est nul, alors R2 est nul.

  • Si R1 est un type primitif, alors R2 est identique à R1.

  • Si R1 est un type de référence, alors:

    • R1 est un sous-type de R2 ou R1 peut être converti en un sous-type de R2 par conversion non contrôlée (§5.1.9), ou

    • R1 = | R2 |

("| R2 |" se réfère à l'effacement de R2, tel que défini dans §4.6 du JLS .)


* Avant Java 5, Java avait les types de retour invariant, ce qui signifiait le type de retour d'une substitution de méthode nécessaire pour correspondre exactement à la méthode en cours de substitution.

149
Laurence Gonsalves

Oui, cela peut différer, mais il y a quelques limitations.

Avant Java 5.0, lorsque vous substituez une méthode, les paramètres et le type de retour doivent correspondre exactement. En Java 5.0, il introduit une nouvelle fonction appelée type de retour covariant. Vous pouvez remplacer une méthode avec la même signature, mais renvoie une sous-classe de l'objet renvoyé. En d'autres termes, une méthode d'une sous-classe peut renvoyer un objet dont le type est une sous-classe du type renvoyé par la méthode avec la même signature dans la superclasse.

19
Pankaj Goyal

Oui, s'ils renvoient un sous-type. Voici un exemple:

package com.sandbox;

public class Sandbox {

    private static class Parent {
        public ParentReturnType run() {
            return new ParentReturnType();
        }
    }

    private static class ParentReturnType {

    }

    private static class Child extends Parent {
        @Override
        public ChildReturnType run() {
            return new ChildReturnType();
        }
    }

    private static class ChildReturnType extends ParentReturnType {
    }
}

Ce code est compilé et exécuté.

18
Daniel Kaplan

De manière générale, oui, le type de méthode de renvoi renvoyé peut être différent. Mais ce n'est pas simple, il y a des cas impliqués.

Cas 1: Si le type de retour est un type de données primitif ou un vide.

Sortie: Si le type de retour est void ou primitive, le type de données de la méthode de la classe parent et de la méthode de substitution doit être identique . E.g. si le type de retour est int, float, string, alors il devrait être identique

Cas 2: Si le type de retour est un type de données dérivé:

Sortie: Si le type de retour de la méthode de classe parent est un type dérivé, le type de retour de la méthode de remplacement est identique au type de données dérivé de la sous-classe par rapport au type de données dérivé . E.g. Supposons que j'ai une classe A B est la sous-classe de A C est la sous-classe de B D est la sous-classe de C puis, si si la super-classe renvoie le type A, la méthode prioritaire est la sous-classe peut renvoyer le type A, B, C ou D, c’est-à-dire ses sous-types. Ceci est aussi appelé covarience.

6
Avinav Mishra

oui C'est possible. Le type de retours peut être différent uniquement si le type de retour de la méthode de la classe parente est
un super type de type de retour de méthode de classe enfant ..
veux dire 

            class ParentClass {
                  public Circle() method1() {
                    return new Cirlce();
                  }
            }

            class ChildClass extends ParentClass {
                  public Square method1() {
                     return new Square();
               }
            }


            Class Cirlce {

            }

            class Square extends Circle {

            }

        ---

Si tel est le cas, un type de retour différent peut être autorisé ...

Types de substitution et de retour, et retours Covariant  
la sous-classe doit définir une méthode qui correspond exactement à la version héritée. Ou, à partir de Java 5, vous êtes autorisé à modifier le type de retour dans le 

exemple de code


                                                                                                            class Alpha {
          Alpha doStuff(char c) {
                  return new Alpha();
              }
           }
             class Beta extends Alpha {
                    Beta doStuff(char c) { // legal override in Java 1.5
                    return new Beta();
                    }
             } } 
A partir de Java 5, ce code sera compilé. Si vous essayez de compiler ce code avec un compilateur 1.4, essayez d'utiliser un type de retour incompatible - sandeep1987 il y a 1 min

2
sandeep1987

Le type de retour doit être identique à, ou un sous-type du type de retour déclaré dans la méthode surchargée d'origine dans la superclasse.

2
sandeep1987

OUI cela peut être possible 

class base {

 base show(){

System.out.println("base class");

return new base();

}
}

class sub extends base{

sub show(){

    System.out.println("sub class");

    return new sub();

 }
}

class inheritance{

 public static void main(String []args) {

        sub obj=new sub();

            obj.show();
 }
}
1
Rahul Bhadana

eh bien, la réponse est oui et non.

dépend de la question. Tout le monde ici a répondu à Java> = 5, et certains ont mentionné que Java <5 ne propose pas de types de retour covariants.

en fait, la spécification de langage Java> = 5 le prend en charge, mais pas le runtime Java. en particulier, la machine virtuelle Java n'a pas été mise à jour pour prendre en charge les types de retour covariants.

dans ce qui était alors considéré comme un geste "intelligent" mais qui a fini par être l’une des pires décisions en matière de conception de l’histoire de Java, Java 5 a implémenté un ensemble de nouvelles fonctionnalités de langage sans aucune modification de la spécification JVM ou classfile. au lieu de cela, toutes les fonctionnalités ont été implémentées dans javac avec des astuces: le compilateur génère/utilise des classes simples pour les classes imbriquées/internes, la suppression et le typage des génériques, des accesseurs synthétiques pour "l'amitié" imbriquée/interne des classes internes, des champs d'instances synthétiques pour "this" pointeurs, champs statiques synthétiques pour les littéraux '.class', etc., etc.

et les types de retour covariants est encore un sucre plus syntaxique ajouté par javac.

par exemple, en compilant ceci:

class Base {
  Object get() { return null; }
}

class Derived extends Base {
  @Override
  @SomeAnnotation
  Integer get() { return null; }
}

javac générera deux méthodes get dans la classe Derived:

Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }

la méthode de pont générée (marquée synthetic et bridge dans le bytecode) est ce qui remplace en réalité Object:Base:get() car, pour la machine virtuelle Java, les méthodes avec différents types de retour sont complètement indépendantes et ne peuvent pas se remplacer. pour fournir le comportement attendu, le pont appelle simplement votre méthode "réelle". Dans l'exemple ci-dessus, javac annotera les méthodes bridge et real dans Dérivé avec @SomeAnnotation.

notez que vous ne pouvez pas coder manuellement cette solution dans Java <5, car les méthodes bridge et real ne diffèrent que par le type de résultat et ne peuvent donc pas coexister dans un programme Java. mais dans le monde de la JVM, les types de retour de méthode font partie de la signature de la méthode (tout comme leurs arguments), de sorte que les deux méthodes portant le même nom et prenant les mêmes arguments sont néanmoins considérées comme totalement indépendantes par la JVM en raison de leurs types de retour différents, et peut coexister.

(BTW, les types de champs font également partie de la signature de champ dans le bytecode, il est donc légal d’avoir plusieurs champs de types différents mais portant le même nom dans une même classe de bytecode.)

pour répondre pleinement à votre question: la machine virtuelle Java ne prend pas en charge les types de retour covariants, mais javac> = 5 le simule au moment de la compilation avec une couche de sucre syntactique doux.

0
Lanchon

Oui. Il est possible que les méthodes substituées aient un type de retour différent.

Mais les limitations sont que la méthode substituée doit avoir un type de retour qui est un type plus spécifique du type de retour de la méthode réelle.

Toutes les réponses ont donné des exemples de la méthode substituée pour avoir un type de retour qui est une sous-classe du type de retour de la méthode réelle.

Par exemple :

public class Foo{

   //method which returns Foo
  Foo getFoo(){
      //your code         
  }

}

 public class subFoo extends Foo{

  //Overridden method which returns subclass of Foo
  @Override
  subFoo getFoo(){
      //your code         
  }

}

Mais cela ne se limite pas aux classes subclass.Even qui implémentent une interface sont un type spécifique de l'interface et peuvent donc être un type de retour dans lequel l'interface est attendue.

Par exemple :

public interface Foo{

   //method which returns Foo
  Foo getFoo();

}

 public class Fizz implements Foo{

  //Overridden method which returns Fizz(as it implements Foo)
  @Override
  Fizz getFoo(){
      //your code         
  }

}
0
Sachin Kumar

Oui on peut en avoir! Le type de retour Covariant est l’un des exemples courants.

0
user11198642