Bisakah metode yang diganti berbeda dalam jenis pengembalian?

134

Bisakah metode yang ditimpa memiliki tipe pengembalian yang berbeda ?

santidoo
sumber
2
Jika Anda tidak memiliki tipe pengembalian yang sama atau lebih sempit, maka Anda akan mendapatkan ::error: method() in subclass cannot override method() in superclass
Quazi Irfan

Jawaban:

176

Java mendukung * tipe kembali kovarian untuk metode ditimpa. Ini berarti metode yang diganti mungkin memiliki tipe pengembalian yang lebih spesifik. Yaitu, selama tipe pengembalian baru dapat ditetapkan untuk jenis kembali metode yang Anda timpa, itu diperbolehkan.

Sebagai contoh:

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

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

Ini ditentukan dalam bagian 8.4.5 dari Spesifikasi Bahasa Jawa :

Jenis kembali dapat bervariasi antara metode yang menimpa satu sama lain jika jenis kembali adalah jenis referensi. Gagasan pengembalian-jenis-substitusi mendukung pengembalian kovarian, yaitu, spesialisasi jenis kembali ke subtipe.

Deklarasi metode d1 dengan tipe kembali R1 adalah tipe-kembali-dapat diganti untuk metode lain d2 dengan tipe kembali R2, jika dan hanya jika kondisi berikut ini berlaku:

  • Jika R1 batal maka R2 batal.

  • Jika R1 adalah tipe primitif, maka R2 identik dengan R1.

  • Jika R1 adalah tipe referensi, maka:

    • R1 adalah subtipe R2 atau R1 dapat dikonversi ke subtipe R2 dengan konversi yang tidak dicentang (§5.1.9), atau

    • R1 = | R2 |

("| R2 |" mengacu pada penghapusan R2, sebagaimana didefinisikan dalam §4.6 dari JLS .)


* Sebelum Java 5, Java memiliki tipe-tipe return yang invarian , yang berarti tipe return dari metode override yang diperlukan agar sama persis dengan metode yang diganti.

Laurence Gonsalves
sumber
26

Ya mungkin berbeda tetapi ada beberapa batasan.

Sebelum Java 5.0, saat Anda mengganti metode, parameter dan tipe pengembalian harus sama persis. Di Java 5.0, ia memperkenalkan fasilitas baru yang disebut tipe pengembalian kovarian. Anda bisa mengganti metode dengan tanda tangan yang sama tetapi mengembalikan subclass dari objek yang dikembalikan. Dengan kata lain, metode dalam subkelas dapat mengembalikan objek yang tipenya adalah subkelas dari jenis yang dikembalikan oleh metode dengan tanda tangan yang sama di dalam superclass.

Pankaj Goyal
sumber
20

Ya, jika mereka mengembalikan subtipe. Ini sebuah contoh:

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

Kode ini mengkompilasi dan menjalankan.

Daniel Kaplan
sumber
9

Secara garis besar ya jenis pengembalian metode utama bisa berbeda. Tapi itu tidak lurus ke depan karena ada beberapa kasus yang terlibat dalam hal ini.

Kasus 1: Jika tipe pengembalian adalah tipe data primitif atau batal.

Output: Jika tipe kembali batal atau primitif maka tipe data metode kelas induk dan metode utama harus sama. misalnya jika tipe pengembaliannya adalah int, float, string maka harus sama

Kasus 2: Jika tipe pengembalian adalah tipe data turunan:

Keluaran: Jika tipe kembalinya dari metode kelas induk adalah tipe turunan maka tipe kembalinya dari metode utama adalah tipe data turunan yang sama dari subkelas dengan tipe data turunan. Misalkan saya memiliki kelas A, B adalah subkelas ke A, C adalah subkelas ke B dan D adalah subkelas ke C; kemudian jika kelas super mengembalikan tipe A maka metode overriding adalah subclass dapat mengembalikan tipe A, B, C atau D yaitu sub-jenisnya. Ini juga disebut sebagai kovarians.

Avinav Mishra
sumber
Anda komentar ini ambigu saya punya kelas AB adalah subclass ke AC adalah subclass ke BD, apa artinya Kelas AB adalah subclass dari AC atau A, B adalah Subclass dari A, C Artinya membingungkan
dinesh kandpal
5

ya itu mungkin .. tipe pengembalian bisa berbeda hanya jika metode kelas induk jenis kembali adalah
tipe super dari jenis metode kelas anak ..
berarti

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

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

Class Circle {

}

class Square extends Circle {

}


Jika ini adalah jenis pengembalian yang berbeda dapat diizinkan ...

Achilles Ram Nakirekanti
sumber
2

baik, jawabannya adalah ya ... DAN TIDAK.

tergantung pertanyaannya. semua orang di sini menjawab tentang Java> = 5, dan beberapa menyebutkan bahwa Java <5 tidak memiliki tipe kovarian.

sebenarnya, spesifikasi bahasa Java> = 5 mendukungnya, tetapi runtime Java tidak. khususnya, JVM tidak diperbarui untuk mendukung tipe pengembalian kovarian.

dalam apa yang dilihat kemudian sebagai langkah "pintar" tetapi akhirnya menjadi salah satu keputusan desain terburuk dalam sejarah Jawa, Java 5 mengimplementasikan banyak fitur bahasa baru tanpa memodifikasi JVM atau spesifikasi classfile sama sekali. alih-alih semua fitur diimplementasikan dengan tipu daya di javac: kompilator menghasilkan / menggunakan kelas polos untuk kelas bersarang / bagian dalam, menghapus tipe dan gips untuk generik, pengakses sintetis untuk "persahabatan" pribadi bersarang / kelas dalam, bidang instance sintetis untuk bagian luar 'ini' pointer, bidang statis sintetik untuk literal '.class', dll., dll.

dan tipe kovarian kembali adalah gula sintaksis yang ditambahkan oleh javac.

misalnya, saat kompilasi ini:

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

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

javac akan menampilkan dua metode get di kelas Derived:

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

metode jembatan yang dihasilkan (ditandai syntheticdan bridgedalam bytecode) adalah apa yang sebenarnya ditimpa Object:Base:get()karena, untuk JVM, metode dengan tipe pengembalian yang berbeda sepenuhnya independen dan tidak dapat saling menimpa. untuk memberikan perilaku yang diharapkan, jembatan hanya memanggil metode "nyata" Anda. pada contoh di atas, javac akan menjelaskan metode bridge dan real di Derived dengan @SomeAnnotation.

perhatikan bahwa Anda tidak dapat membuat kode tangan solusi ini di Java <5, karena metode jembatan dan nyata hanya berbeda dalam jenis pengembalian dan karenanya mereka tidak dapat hidup berdampingan dalam program Java. tetapi di dunia JVM, tipe metode pengembalian adalah bagian dari tanda tangan metode (seperti argumen mereka) dan kedua metode yang bernama sama dan mengambil argumen yang sama tetap dianggap sepenuhnya independen oleh JVM karena jenis pengembalian yang berbeda, dan bisa hidup berdampingan.

(BTW, jenis bidang adalah bagian yang sama dari tanda tangan bidang dalam bytecode, jadi adalah sah untuk memiliki beberapa bidang dari jenis yang berbeda tetapi dinamai sama dalam satu kelas bytecode.)

jadi untuk menjawab pertanyaan Anda sepenuhnya: JVM tidak mendukung tipe pengembalian kovarian, tetapi javac> = 5 memalsukannya pada waktu kompilasi dengan lapisan gula sintaksis manis.

Lanchon
sumber
1

Overriding dan Return Types, dan Covariant Returns
subclass harus mendefinisikan metode yang cocok dengan versi yang diwarisi dengan tepat. Atau, pada Java 5, Anda diizinkan untuk mengubah jenis pengembalian di

Kode sampel


                                                                                                            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, kode ini akan dikompilasi. Jika Anda mencoba untuk mengkompilasi kode ini dengan kompiler 1.4 akan mengatakan mencoba menggunakan jenis pengembalian yang tidak kompatibel - sandeep1987 1 mnt yang lalu

sandeep1987
sumber
1

Jawaban lainnya semuanya benar, tetapi secara mengejutkan semua meninggalkan aspek teoritis di sini: tipe pengembalian dapat berbeda, tetapi mereka hanya dapat membatasi jenis yang digunakan dalam kelas super karena Prinsip Substitusi Liskov .

Ini sangat sederhana: ketika Anda memiliki kode "klien" yang memanggil beberapa metode:

int foo = someBar.bar();

maka hal di atas harus bekerja (dan mengembalikan sesuatu yang inttidak peduli implementasi mana yang bar()diminta).

Artinya: jika ada subkelas Bar yang menggantikan bar()maka Anda masih harus mengembalikan sesuatu yang tidak merusak "kode pemanggil".

Dengan kata lain: asumsikan bahwa basis bar()seharusnya mengembalikan int. Kemudian subkelas bisa kembalishort - tetapi bukan longkarena penelepon akan baik-baik saja berurusan dengan shortnilai, tetapi bukan long!

GhostCat
sumber
0

Jenis kembali harus sama dengan, atau subtipe dari, jenis kembali dinyatakan dalam metode override asli dalam superclass.

sandeep1987
sumber
5
Anda harus menggabungkan dua jawaban Anda.
theblang
0

YA itu mungkin

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
sumber
0

Iya. Dimungkinkan untuk metode yang diganti untuk memiliki tipe pengembalian yang berbeda.

Tetapi keterbatasannya adalah bahwa metode yang diganti harus memiliki tipe pengembalian yang lebih spesifik dari jenis kembali dari metode aktual.

Semua jawaban telah memberikan contoh metode override untuk memiliki tipe kembali yang merupakan subkelas dari tipe kembali dari metode aktual.

Sebagai contoh :

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         
  }

}

Tapi ini tidak hanya terbatas pada subkelas. Bahkan kelas yang mengimplementasikan antarmuka adalah tipe antarmuka tertentu dan dengan demikian dapat menjadi tipe pengembalian di mana antarmuka diharapkan.

Sebagai contoh :

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
sumber
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
sumber
Bagaimana ini menjawab pertanyaan?
Manchester tanpa merek
ini adalah contoh dari tipe pengembalian yang berbeda.
Parth