Чи можуть переоцінені методи відрізнятися за типом повернення?


134

Чи можуть переоцінені методи мати різні типи повернення ?


2
Якщо у вас немає однакового або вужчого типу повернення, ви отримаєте ::error: method() in subclass cannot override method() in superclass
Quazi Irfan

Відповіді:


176

Java підтримує * коваріантні типи повернення для перекритих методів. Це означає, що перекритий метод може мати більш конкретний тип повернення. Тобто, доки новий тип повернення присвоюється типу повернення методу, який ви переосмислюєте, це дозволено.

Наприклад:

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

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

Це вказано в розділі 8.4.5 Специфікації мови Java :

Типи повернення можуть відрізнятися між методами, які перекривають один одного, якщо типи повернення є типовими типами. Поняття зворотної замінюваності типу підтримує коваріантні повернення, тобто спеціалізацію типу повернення до підтипу.

Оголошення методу d1 з типом повернення R1 може бути замінено типом повернення для іншого методу d2 з типом повернення R2, ​​якщо і тільки в тому випадку, якщо виконуються наступні умови:

  • Якщо R1 недійсний, то R2 недійсний.

  • Якщо R1 є примітивним типом, то R2 ідентичний R1.

  • Якщо R1 є еталонним типом, тоді:

    • R1 є або підтипом R2, або R1 може бути перетворений у підтип R2 шляхом некерованого перетворення (§5.1.9), або

    • R1 = | R2 |

("| R2 |" відноситься до стирання R2, ​​визначеного в §4.6 JLS .)


* До Java 5 у Java були інваріантні типи повернення, що означало тип повернення методу, який було замінено, необхідного для того, щоб точно відповідати методу, який перекрито.


26

Так, це може відрізнятися, але вони є деякими обмеженнями.

Перед Java 5.0, коли ви перекриєте метод, обидва параметри і тип повернення повинні точно відповідати. У Java 5.0 він впроваджує новий об'єкт під назвою тип коваріантного повернення. Ви можете замінити метод з однаковою підписом, але повертає підклас повернутого об'єкта. Іншими словами, метод підкласу може повернути об’єкт, тип якого є підкласом типу, повернутий методом з однаковою підписом у надкласі.


20

Так, якщо вони повернуть підтип. Ось приклад:

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

Цей код складається і запускається.


9

Загалом, так, тип повернення переважаючого методу може бути різним. Але це не прямо, оскільки в цьому є деякі випадки.

Випадок 1: Якщо тип повернення є примітивним типом даних або недійсним.

Вихід: Якщо тип повернення недійсний або примітивний, тип даних методу батьківського класу та методу переосмислення повинні бути однаковими. наприклад, якщо тип повернення - int, float, string, то він повинен бути однаковим

Випадок 2: Якщо тип повернення є похідним типом даних:

Вихід: Якщо тип повернення методу батьківського класу є похідним типом, то тип повернення методу переосмислення є тим самим похідним типом даних підкласу до похідного типу даних. Наприклад, припустимо, що у мене є клас A, B є підкласом до A, C є підкласом до B і D є підкласом до C; тоді, якщо суперклас повертає тип А, тоді метод переосмислення підкласу може повертати тип A, B, C або D, тобто його підтипи. Це також називається коваріацією.


ваш цей коментар неоднозначний, у мене клас АВ є підкласом, AC є підкласом BD, що це означає, клас AB є підкласом AC або A, B є підкласом A, C означає його заплутаність
dinesh kandpal

5

Так , це можливо .. тип повертається може відрізнятися тільки якщо метод батьківського класу повертається тип
супер тип дитячого класу метод поворотного типу ..
засіб

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

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

Class Circle {

}

class Square extends Circle {

}


Якщо це тоді можливий різний тип повернення ...


2

ну, відповідь - так ... І НІ.

залежить від питання. всі тут відповіли стосовно Java> = 5, а деякі згадували, що Java <5 не містить коваріантних типів повернення.

насправді специфікація мови Java> = 5 підтримує його, але час виконання Java не робить. зокрема, JVM не оновлювався для підтримки коваріантних типів повернення.

в тому, що тоді розглядалося як "розумний" крок, але в кінцевому підсумку було одним з найгірших дизайнерських рішень в історії Java, Java 5 реалізувала купу нових мовних функцій, не змінюючи JVM або специфікацію класного файлу взагалі. натомість усі функції були реалізовані з хитрістю у javac: компілятор генерує / використовує прості класи для вкладених / внутрішніх класів, тип стирання та кастинг для дженериків, синтетичні аксесуари для вкладених / внутрішніх класів приватної "дружби", синтетичні екземплярні поля для зовнішнього "цього" покажчики, синтетичні статичні поля для літератур '.class' тощо, тощо.

і коваріантний тип повернення - це ще синтаксичний цукор, який додає javac.

наприклад, при компілюванні цього:

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

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

javac виведе два методи отримання в класі Derived:

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

створений метод мосту (позначений syntheticі bridgeв байт-коді) - це те, що насправді перекриває, Object:Base:get()оскільки для JVM методи з різними типами повернення є абсолютно незалежними і не можуть перекривати один одного. щоб забезпечити очікувану поведінку, міст просто називає ваш "реальний" метод. у наведеному вище прикладі javac буде анотувати як мостові, так і реальні методи в Похідному з @SomeAnnotation.

зауважте, що ви не можете вручну кодувати це рішення в Java <5, оскільки мостові та реальні методи відрізняються лише типом повернення, і тому вони не можуть співіснувати в програмі Java. але у світі JVM типи повернення методів є частиною підпису методу (подібно до їх аргументів), і тому два методи названі однаковими та беручи однакові аргументи, проте, вони сприймаються як абсолютно незалежні JVM через їх різні типи повернення, і може співіснувати.

(BTW, типи полів однаково є частиною підпису поля в байт-коді, тому законно мати кілька полів різних типів, але названих однаковими в одному байтовому класі.)

тож, щоб відповісти на ваше запитання повністю: JVM не підтримує коваріантні типи повернення, але javac> = 5 підробляє його під час компіляції з покриттям із солодкого синтаксичного цукру.


1

Типи перевизначення та повернення та Коваріант Повертає
підклас повинен визначати метод, який точно відповідає успадкованій версії. Або, як і в Java 5, ви можете змінювати тип повернення в

зразок коду


                                                                                                            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, цей код буде складено. Якщо ви намагалися скомпілювати цей код із компілятором 1.4, скажіть, що намагаєтесь використовувати несумісний тип повернення - sandeep1987 1 хв тому


1

Інші відповіді вірні, але дивно, що тут не залишається теоретичний аспект: типи повернення можуть бути різними, але вони можуть обмежувати тип, який використовується у суперкласі через Принцип заміни Ліскова .

Це дуже просто: коли у вас є "клієнтський" код, який викликає якийсь метод:

int foo = someBar.bar();

то вищезазначене має спрацювати (і повернути те, що не intмає значення, на яку реалізацію bar()звертається).

Значення: якщо є підклас Bar, який переосмислює, bar()то вам все одно потрібно повернути те, що не порушує "код виклику".

Іншими словами: припустимо, що база bar()повинна повертатися до int. Тоді підклас може повернутися short- але не longтому, що абонентам буде добре мати справу зі shortзначенням, але не long!


0

Тип повернення повинен бути таким самим, як або підтип зворотного типу, оголошеного в початковому методі переосмислення в надкласі.


5
Вам слід поєднати дві відповіді.
theblang

0

ТАК це можливо

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

Так. Можливо, що переосмислені методи мають різний тип повернення.

Але обмеження полягають у тому, що перекритий метод повинен мати тип повернення, який є більш конкретним типом типу повернення фактичного методу.

У всіх відповідях наведено приклади переопределеного методу, щоб мати тип повернення, який є підкласом типу повернення фактичного методу.

Наприклад :

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         
  }

}

Але це не обмежується лише підкласом. Навіть класи, які реалізують інтерфейс, є певним типом інтерфейсу, і таким чином можуть бути типом повернення, де очікується інтерфейс.

Наприклад :

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

Як це відповідає на питання?
Матч Манчестер

це приклад різного типу повернення.
Parth
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.