I metodi sostituiti possono differire nel tipo restituito?


134

I metodi sovrascritti possono avere tipi di restituzione diversi ?


2
Se non hai lo stesso tipo di restituzione o più stretto, otterrai ::error: method() in subclass cannot override method() in superclass
Quazi Irfan,

Risposte:


176

Java supporta * tipi di restituzione covarianti per metodi sostituiti. Ciò significa che un metodo ignorato può avere un tipo di ritorno più specifico. Cioè, fintanto che il nuovo tipo restituito è assegnabile al tipo restituito del metodo che si sta sostituendo, è consentito.

Per esempio:

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

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

Questo è specificato nella sezione 8.4.5 della specifica del linguaggio Java :

I tipi di restituzione possono variare tra i metodi che si sostituiscono reciprocamente se i tipi di restituzione sono tipi di riferimento. La nozione di sostituibilità del tipo restituito supporta i rendimenti covarianti, ovvero la specializzazione del tipo restituito in un sottotipo.

Una dichiarazione di metodo d1 con tipo di ritorno R1 è sostituibile con tipo di ritorno per un altro metodo d2 con tipo di ritorno R2, se e solo se valgono le seguenti condizioni:

  • Se R1 è nullo, allora R2 è nullo.

  • Se R1 è un tipo primitivo, allora R2 è identico a R1.

  • Se R1 è un tipo di riferimento, allora:

    • R1 è un sottotipo di R2 o R1 può essere convertito in un sottotipo di R2 mediante conversione non controllata (§5.1.9), oppure

    • R1 = | R2 |

("| R2 |" si riferisce alla cancellazione di R2, come definita al § 4.6 del JLS .)


* Prima di Java 5, Java aveva tipi di restituzione invarianti , il che significava che il tipo di restituzione di una sostituzione del metodo era necessario per corrispondere esattamente al metodo da sostituire.


26

Sì, può essere diverso ma ci sono alcune limitazioni.

Prima di Java 5.0, quando si sovrascrive un metodo, sia i parametri che il tipo restituito devono corrispondere esattamente. In Java 5.0 introduce una nuova funzione chiamata tipo di ritorno covariante. È possibile sovrascrivere un metodo con la stessa firma ma restituisce una sottoclasse dell'oggetto restituito. In altre parole, un metodo in una sottoclasse può restituire un oggetto il cui tipo è una sottoclasse del tipo restituito dal metodo con la stessa firma nella superclasse.


20

Sì, se restituiscono un sottotipo. Ecco un esempio:

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 {
    }
}

Questo codice viene compilato ed eseguito.


9

In linea di massima, il tipo di ritorno del metodo di sostituzione può essere diverso. Ma non è semplice in quanto vi sono alcuni casi coinvolti in questo.

Caso 1: se il tipo restituito è un tipo di dati primitivo o nullo.

Output: se il tipo restituito è nullo o primitivo, il tipo di dati del metodo della classe genitore e del metodo di sostituzione dovrebbe essere lo stesso. ad es. se il tipo restituito è int, float, string, dovrebbe essere lo stesso

Caso 2: se il tipo restituito è derivato, digitare il tipo di dati:

Output: se il tipo restituito del metodo della classe padre viene derivato, il tipo restituito del metodo di sostituzione è lo stesso tipo di dati derivati ​​della sottoclasse del tipo di dati derivati. es. Supponiamo che io abbia una classe A, B sia una sottoclasse di A, C sia una sottoclasse di B e D sia una sottoclasse di C; quindi se la superclasse sta restituendo il tipo A, il metodo di override è la sottoclasse può restituire il tipo A, B, C o D, ovvero i suoi sottotipi. Questo è anche chiamato covarianza.


il tuo questo commento è ambiguo ho una classe AB è una sottoclasse di AC è una sottoclasse di BD, cosa significa che la Classe AB è una sottoclasse di AC o A, B sono una sottoclasse di A, C Significa che è confusa
dinesh kandpal

5

sì È possibile .. il tipo di restituzione può essere diverso solo se il tipo di restituzione del metodo di classe genitore è
un super tipo di tipo di restituzione del metodo di classe figlio ..
significa

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

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

Class Circle {

}

class Square extends Circle {

}


Se questo è il tipo di ritorno diverso può essere consentito ...


2

beh, la risposta è sì ... E NO.

dipende dalla domanda. tutti qui hanno risposto riguardo a Java> = 5, e alcuni hanno detto che Java <5 non presenta tipi di ritorno covarianti.

in realtà, la specifica del linguaggio Java> = 5 la supporta, ma il runtime Java no. in particolare, la JVM non è stata aggiornata per supportare i tipi di restituzione covarianti.

in quella che è stata poi vista come una mossa "intelligente", ma alla fine è stata una delle peggiori decisioni di progettazione nella storia di Java, Java 5 ha implementato un sacco di nuove funzionalità linguistiche senza modificare affatto la JVM o le specifiche del file di classe. invece tutte le funzionalità sono state implementate con inganno in javac: il compilatore genera / usa classi semplici per classi nidificate / interne, cancellazione di tipi e calchi per generici, accessori sintetici per "amicizia" privata di classe nidificata / interna, campi di istanza sintetici per esterno "questo" puntatori, campi statici sintetici per valori letterali ".class", ecc., ecc.

e i tipi di ritorno covarianti sono ancora più zucchero sintattico aggiunto da javac.

ad esempio, durante la compilazione di questo:

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

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

javac produrrà due metodi get nella classe Derived:

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

il metodo bridge generato (contrassegnato synthetic e bridgein bytecode) è ciò che sostituisce effettivamente Object:Base:get()perché, per la JVM, i metodi con diversi tipi di ritorno sono completamente indipendenti e non possono sostituirsi. per fornire il comportamento previsto, il bridge chiama semplicemente il tuo metodo "reale". nell'esempio sopra, javac annoterà sia i bridge che i metodi reali in Derivato con @SomeAnnotation.

si noti che non è possibile codificare manualmente questa soluzione in Java <5, poiché i bridge e i metodi reali differiscono solo nel tipo restituito e quindi non possono coesistere in un programma Java. ma nel mondo JVM, i tipi di restituzione del metodo fanno parte della firma del metodo (proprio come i loro argomenti) e quindi i due metodi denominati uguali e prendendo gli stessi argomenti sono comunque visti come completamente indipendenti dalla JVM a causa dei loro diversi tipi di restituzione, e può coesistere.

(A proposito, i tipi di campi fanno parte in modo simile della firma del campo in bytecode, quindi è legale avere diversi campi di tipi diversi ma denominati uguali all'interno di una singola classe bytecode.)

quindi per rispondere pienamente alla tua domanda: la JVM non supporta tipi di ritorno covarianti, ma javac> = 5 la falsifica in fase di compilazione con un rivestimento di zucchero sintattico dolce.


1

Sostituzione e tipi di ritorno e ritorni covarianti
la sottoclasse deve definire un metodo che corrisponda esattamente alla versione ereditata. Oppure, a partire da Java 5, è consentito modificare il tipo di ritorno in

codice di esempio


                                                                                                            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, questo codice verrà compilato. Se si dovesse tentare di compilare questo codice con un compilatore 1.4, verrà indicato il tentativo di utilizzare un tipo di ritorno incompatibile - sandeep1987 1 min fa


1

Le altre risposte sono tutte corrette, ma sorprendentemente tutte tralasciando l'aspetto teorico qui: i tipi di ritorno possono essere diversi, ma possono limitare il tipo usato nella superclasse solo a causa del principio di sostituzione di Liskov .

È super semplice: quando hai un codice "client" che chiama un metodo:

int foo = someBar.bar();

quindi quanto sopra deve funzionare (e restituire qualcosa che intnon importa quale implementazione di bar()viene invocata).

Significato: se esiste una sottoclasse Bar che ha la precedenza, bar()è comunque necessario restituire qualcosa che non interrompe il "codice chiamante".

In altre parole: supponiamo che la base bar()dovrebbe restituire int. Quindi potrebbe tornare una sottoclasse short, ma non longperché i chiamanti andranno bene a gestire un shortvalore, ma non un long!


0

Il tipo restituito deve essere lo stesso o un sottotipo del tipo restituito dichiarato nel metodo sovrascritto originale nella superclasse.


5
Dovresti combinare le tue due risposte.
theblang,

0

SÌ, può essere possibile

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();
 }
}

0

Sì. È possibile che i metodi sostituiti abbiano un tipo di ritorno diverso.

Ma i limiti sono che il metodo ignorato deve avere un tipo restituito che è il tipo più specifico del tipo restituito del metodo effettivo.

Tutte le risposte hanno fornito esempi del metodo ignorato per avere un tipo restituito che è una sottoclasse del tipo restituito del metodo effettivo.

Per esempio :

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         
  }

}

Ma questo non è limitato solo alla sottoclasse. Anche le classi che implementano un'interfaccia sono un tipo specifico dell'interfaccia e quindi possono essere un tipo di ritorno in cui è prevista l'interfaccia.

Per esempio :

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
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();
    }
}

Come risponde alla domanda?
Manchester senza marchio

questo è l'esempio di diverso tipo di ritorno.
Parth
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.