Les méthodes remplacées peuvent-elles différer dans le type de retour?

134

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

santidoo
la source
2
Si vous n'avez pas le même type de retour ou un type de retour plus étroit, vous obtiendrez ::error: method() in subclass cannot override method() in superclass
Quazi Irfan

Réponses:

176

Java prend en charge les types de retour * covariants pour les méthodes remplacées. Cela signifie qu'une méthode remplacée peut avoir un plus type de retour spécifique. Autrement dit, tant que le nouveau type de retour est attribuable au type de retour de la méthode que vous remplacez, 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 les unes aux autres si les types de retour sont des types référence. La notion de substituabilité du type de retour prend en charge les retours covariants, c'est-à-dire la spécialisation du type de retour vers un sous-type.

Une déclaration de méthode d1 avec le type de retour R1 est substituable au 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, 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 vérifiée (§5.1.9), ou

    • R1 = | R2 |

("| R2 |" fait référence à l'effacement de R2, tel que défini au §4.6 du JLS .)


* Avant Java 5, Java avait des types de retour invariants , ce qui signifiait le type de retour d'un remplacement de méthode nécessaire pour correspondre exactement à la méthode remplacée.

Laurence Gonsalves
la source
26

Oui, cela peut différer, mais il y a certaines limites.

Avant Java 5.0, lorsque vous remplacez une méthode, les paramètres et le type de retour doivent correspondre exactement. Dans Java 5.0, il introduit une nouvelle fonctionnalité 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 dans une sous-classe peut retourner un objet dont le type est une sous-classe du type retourné par la méthode avec la même signature dans la superclasse.

Pankaj Goyal
la source
20

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 se compile et s'exécute.

Daniel Kaplan
la source
9

En gros, le type de retour oui de la méthode de remplacement peut être différent. Mais ce n'est pas simple car il y a des cas impliqués dans cela.

Cas 1: si le type de retour est un type de données primitif ou void.

Sortie: Si le type de retour est vide ou primitif, le type de données de la méthode de classe parent et de la méthode de remplacement doit être le même. Par exemple, si le type de retour est int, float, string alors il devrait être le même

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 substitution est le même type de données dérivé de la sous-classe que le type de données dérivé. Par exemple, supposons que j'ai une classe A, B est une sous-classe de A, C est une sous-classe de B et D est une sous-classe de C; alors si la super classe retourne le type A, alors la méthode de substitution est la sous-classe peut retourner le type A, B, C ou D, c'est-à-dire ses sous-types. Ceci est également appelé covariance.

Avinav Mishra
la source
votre ce commentaire est ambigu j'ai une classe AB est une sous-classe à AC est une sous-classe à BD, ce que cela signifie La classe AB est une sous-classe de AC ou A, B est une sous-classe de A, C signifie que c'est déroutant
dinesh kandpal
5

oui C'est possible .. renvoie le type peut être différent uniquement si le type de retour de la méthode de classe parent est
un super type de type de retour de la méthode de classe enfant ..
signifie

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

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

Class Circle {

}

class Square extends Circle {

}


Si tel est le type de retour, un autre type de retour peut être autorisé ...

Achille Ram Nakirekanti
la source
2

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

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

en fait, la spécification du langage Java> = 5 le prend en charge, mais pas l'environnement d'exécution Java. en particulier, la JVM n'a pas été mise à jour pour prendre en charge les types de retour covariants.

dans ce qui était alors considéré comme un mouvement "intelligent" mais qui a fini par être l'une des pires décisions de conception de l'histoire de Java, Java 5 a implémenté un tas de nouvelles fonctionnalités de langage sans modifier la JVM ou la spécification du fichier de classe. au lieu de cela, toutes les fonctionnalités ont été implémentées avec ruse en javac: le compilateur génère / utilise des classes simples pour les classes imbriquées / internes, l'effacement de type et le cast pour les génériques, les accesseurs synthétiques pour la classe nested / interne privée "amitié", les champs d'instance synthétiques pour les 'this' externes pointeurs, champs statiques synthétiques pour les littéraux '.class', etc., etc.

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

par exemple, lors de la compilation de ceci:

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

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

javac affichera 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 syntheticet bridgeen bytecode) est en fait ce qui se substitue Object:Base:get()car, pour la JVM, les méthodes avec différents types de retour sont complètement indépendantes et ne peuvent pas se substituer les unes aux autres. pour fournir le comportement attendu, le pont appelle simplement votre méthode "réelle". dans l'exemple ci-dessus, javac annotera à la fois les méthodes bridge et real dans Derived with @SomeAnnotation.

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

(BTW, les types de champs font également partie de la signature de champ en bytecode, il est donc légal d'avoir plusieurs champs de types différents mais nommés de la même manière dans une seule classe de bytecode.)

donc pour répondre pleinement à votre question: la JVM 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 syntaxique sucré.

Lanchon
la source
1

Remplacer et renvoyer les types et les renvois covariants
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();
                    }
             } } 
Java 5, ce code se compilera. Si vous tentez de compiler ce code avec un compilateur 1.4, vous direz que vous essayez d'utiliser un type de retour incompatible - sandeep1987 il y a 1 min

sandeep1987
la source
1

Les autres réponses sont toutes correctes, mais étonnamment toutes laissant de côté l'aspect théorique ici: les types de retour peuvent être différents, mais ils ne peuvent restreindre le type utilisé dans la super classe qu'à cause du principe de substitution de Liskov .

C'est super simple: quand vous avez du code "client" qui appelle une méthode:

int foo = someBar.bar();

alors ce qui précède doit fonctionner (et renvoyer quelque chose qui est une intn'importe quelle implémentation de bar()est invoquée).

Signification: s'il existe une sous-classe Bar qui remplace, bar()vous devez toujours renvoyer quelque chose qui ne rompt pas le "code de l'appelant".

En d'autres termes: supposons que la base bar()est supposée retourner int. Ensuite, une sous-classe pourrait revenir short- mais pas longparce que les appelants seront bien traités avec une shortvaleur, mais pas un long!

GhostCat
la source
0

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

sandeep1987
la source
5
Vous devez combiner vos deux réponses.
theblang
0

OUI c'est 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();
 }
}
simplePerson43
la source
0

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

Mais les limitations sont que la méthode remplacé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 surchargé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 n'est pas seulement limité aux sous-classes: même les classes qui implémentent une interface sont un type spécifique de l'interface et peuvent donc être un type de retour là où 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         
  }

}
Sachin Kumar
la source
0
class Phone {
    public Phone getMsg() {
        System.out.println("phone...");
        return new Phone();
    }
}

class Samsung extends Phone{
    @Override
    public Samsung getMsg() {
        System.out.println("samsung...");
        return new Samsung();
    }
    
    public static void main(String[] args) {
        Phone p=new Samsung();
        p.getMsg();
    }
}
Parth
la source
Comment cela répond-il à la question?
Unbranded Manchester le
c'est l'exemple d'un type de retour différent.
Parth le