Các phương thức ghi đè có thể khác nhau trong kiểu trả về?


134

Các phương thức ghi đè có thể có các kiểu trả về khác nhau ?


2
Nếu bạn không có loại trả lại giống hoặc hẹp hơn thì bạn sẽ nhận được ::error: method() in subclass cannot override method() in superclass
Quazi Irfan

Câu trả lời:


176

Java hỗ trợ các kiểu trả về * covariant cho các phương thức được ghi đè. Điều này có nghĩa là một phương thức được ghi đè có thể có kiểu trả về cụ thể hơn . Đó là, miễn là loại trả về mới có thể được gán cho loại trả về của phương thức bạn đang ghi đè, điều đó được cho phép.

Ví dụ:

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

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

Điều này được chỉ định trong phần 8.4.5 của Đặc tả ngôn ngữ Java :

Các kiểu trả về có thể khác nhau giữa các phương thức ghi đè lên nhau nếu các kiểu trả về là các kiểu tham chiếu. Khái niệm về khả năng thay thế kiểu trả về hỗ trợ trả về covariant, nghĩa là chuyên môn hóa kiểu trả về cho một kiểu con.

Một khai báo phương thức d1 với kiểu trả về R1 là kiểu trả về có thể thay thế cho phương thức khác d2 với kiểu trả về R2, khi và chỉ khi các điều kiện sau giữ:

  • Nếu R1 là void thì R2 là void.

  • Nếu R1 là loại nguyên thủy, thì R2 giống hệt với R1.

  • Nếu R1 là loại tham chiếu thì:

    • R1 là một kiểu con của R2 hoặc R1 có thể được chuyển đổi thành một kiểu con của R2 bằng cách chuyển đổi không được kiểm tra (§5.1.9) hoặc

    • R 1 = | R2 |

("| R2 |" đề cập đến việc xóa R2, như được định nghĩa trong §4.6 của JLS .)


* Trước Java 5, Java có các kiểu trả về bất biến , có nghĩa là kiểu trả về của ghi đè phương thức cần thiết để khớp chính xác với phương thức được ghi đè.


26

Vâng, nó có thể khác nhau nhưng chúng là một số hạn chế.

Trước Java 5.0, khi bạn ghi đè một phương thức, cả hai tham số và kiểu trả về phải khớp chính xác. Trong Java 5.0, nó giới thiệu một phương tiện mới gọi là kiểu trả về covariant. Bạn có thể ghi đè một phương thức có cùng chữ ký nhưng trả về một lớp con của đối tượng được trả về. Nói cách khác, một phương thức trong một lớp con có thể trả về một đối tượng có kiểu là một lớp con của kiểu được trả về bởi phương thức có cùng chữ ký trong lớp cha.


20

Có, nếu họ trả lại một kiểu con. Đây là một ví dụ:

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

Mã này biên dịch và chạy.


8

Nói rộng ra có kiểu trả về của phương thức ghi đè có thể khác nhau. Nhưng nó không đơn giản vì có một số trường hợp liên quan đến việc này.

Trường hợp 1: Nếu kiểu trả về là kiểu dữ liệu nguyên thủy hoặc khoảng trống.

Đầu ra: Nếu kiểu trả về là void hoặc primitive thì kiểu dữ liệu của phương thức lớp cha và phương thức ghi đè phải giống nhau. ví dụ: nếu kiểu trả về là int, float, chuỗi thì nó phải giống nhau

Trường hợp 2: Nếu kiểu trả về là kiểu dữ liệu dẫn xuất:

Đầu ra: Nếu kiểu trả về của phương thức lớp cha là kiểu dẫn xuất thì kiểu trả về của phương thức ghi đè là cùng kiểu dữ liệu dẫn xuất của lớp con với kiểu dữ liệu dẫn xuất. ví dụ: Giả sử tôi có một lớp A, B là một lớp con cho A, C là một lớp con của B và D là một lớp con của C; sau đó nếu siêu lớp đang trả về loại A thì phương thức ghi đè là lớp con có thể trả về loại A, B, C hoặc D tức là các loại phụ của nó. Điều này cũng được gọi là hiệp phương sai.


Nhận xét của bạn không rõ ràng. Tôi có một lớp AB là lớp con với AC là lớp con của BD, nghĩa là Lớp AB là lớp con của AC hoặc A, B là Lớp con của A, C Có nghĩa là nó khó hiểu
dinesh kandpal

5

vâng Có thể .. lợi nhuận loại có thể khác nhau chỉ khi loại phương thức lớp cha mẹ trở lại là
một loại siêu của con lớp phương pháp kiểu trả về ..
phương tiện

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

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

Class Circle {

}

class Square extends Circle {

}


Nếu đây là loại trả lại khác nhau có thể được cho phép ...


2

tốt, câu trả lời là có ... VÀ KHÔNG.

phụ thuộc vào câu hỏi mọi người ở đây đã trả lời về Java> = 5 và một số người đã đề cập rằng Java <5 không có các kiểu trả về covariant.

thực tế, ngôn ngữ Java spec> = 5 hỗ trợ nó, nhưng thời gian chạy Java thì không. đặc biệt, JVM không được cập nhật để hỗ trợ các kiểu trả về covariant.

trong những gì được coi là một động thái "thông minh" nhưng cuối cùng lại trở thành một trong những quyết định thiết kế tồi tệ nhất trong lịch sử Java, Java 5 đã thực hiện một loạt các tính năng ngôn ngữ mới mà không sửa đổi JVM hoặc specfile class. thay vào đó, tất cả các tính năng được triển khai với mánh khóe trong javac: trình biên dịch tạo / sử dụng các lớp đơn giản cho các lớp lồng nhau / bên trong, kiểu xóa và phôi cho các tổng quát, các trình truy cập tổng hợp cho "tình bạn" riêng của lớp lồng bên trong, các trường đối tượng tổng hợp cho bên ngoài 'này' con trỏ, trường tĩnh tổng hợp cho chữ '. class', v.v., v.v.

và các kiểu trả về covariant là đường cú pháp được thêm bởi javac.

ví dụ: khi biên dịch này:

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

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

javac sẽ xuất ra hai phương thức get trong lớp Derogen:

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

phương thức cầu được tạo (được đánh dấu syntheticbridgebằng mã byte) là những gì thực sự ghi đè Object:Base:get()bởi vì, đối với JVM, các phương thức với các kiểu trả về khác nhau hoàn toàn độc lập và không thể ghi đè lẫn nhau. để cung cấp hành vi dự kiến, cây cầu chỉ cần gọi phương thức "thực" của bạn. trong ví dụ trên, javac sẽ chú thích cả hai phương thức cầu nối và phương thức thực trong Derogen với @SomeAnnotation.

lưu ý rằng bạn không thể mã hóa giải pháp này trong Java <5, bởi vì các phương thức cầu nối và phương thức thực chỉ khác nhau về kiểu trả về và do đó chúng không thể cùng tồn tại trong một chương trình Java. nhưng trong thế giới JVM, các kiểu trả về của phương thức là một phần của chữ ký phương thức (giống như các đối số của chúng) và do đó hai phương thức được đặt tên giống nhau và lấy các đối số giống nhau dù sao cũng được JVM xem là hoàn toàn độc lập do các kiểu trả về khác nhau của chúng, và có thể cùng tồn tại.

(BTW, các loại trường là một phần tương tự của chữ ký trường trong mã byte, do đó, có nhiều trường thuộc các loại khác nhau nhưng được đặt tên giống nhau trong một lớp mã byte đơn.)

Vì vậy, để trả lời câu hỏi của bạn đầy đủ: JVM không hỗ trợ các kiểu trả về covariant, nhưng javac> = 5 giả mạo nó tại thời điểm biên dịch với một lớp phủ cú pháp ngọt.


1

Các kiểu ghi đè và trả về và Covariant Trả về
lớp con phải xác định một phương thức khớp chính xác với phiên bản kế thừa. Hoặc, kể từ Java 5, bạn được phép thay đổi loại trả về trong

mã mẫu


                                                                                                            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, mã này sẽ biên dịch. Nếu bạn định biên dịch mã này bằng trình biên dịch 1.4 sẽ cho biết việc cố gắng sử dụng loại trả về không tương thích - sandeep1987 1 phút trước


1

Các câu trả lời khác đều đúng, nhưng đáng ngạc nhiên là tất cả đều bỏ qua khía cạnh lý thuyết ở đây: các kiểu trả về có thể khác nhau, nhưng chúng chỉ có thể hạn chế loại được sử dụng trong siêu hạng vì Nguyên tắc thay thế Liskov .

Nó rất đơn giản: khi bạn có mã "client" gọi một số phương thức:

int foo = someBar.bar();

sau đó các công việc trên phải hoạt động (và trả lại một cái gì đó intkhông có vấn đề gì khi thực hiện được thực hiện bar()).

Có nghĩa là: nếu có một Bar lớp con đó ghi đè bar()thì bạn vẫn phải trả lại một cái gì đó mà không phá vỡ "mã gọi".

Nói cách khác: giả sử rằng cơ sở bar()được cho là trả về int. Sau đó, một lớp con có thể trở lại short- nhưng không phải longvì người gọi sẽ xử lý tốt với một shortgiá trị, nhưng không phải là a long!


0

Kiểu trả về phải giống như hoặc một kiểu con của kiểu trả về được khai báo trong phương thức ghi đè ban đầu trong lớp bậc trên.


5
Bạn nên kết hợp hai câu trả lời của bạn.
theblang

0

CÓ, nó có thể

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

Đúng. Các phương thức được ghi đè có thể có kiểu trả về khác nhau.

Nhưng những hạn chế là phương thức ghi đè phải có kiểu trả về là kiểu cụ thể hơn của kiểu trả về của phương thức thực tế.

Tất cả các câu trả lời đã đưa ra các ví dụ về phương thức được ghi đè để có kiểu trả về là lớp con của kiểu trả về của phương thức thực tế.

Ví dụ :

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         
  }

}

Nhưng điều này không chỉ giới hạn ở các lớp con. Các lớp thực hiện giao diện là một loại giao diện cụ thể và do đó có thể là loại trả về nơi giao diện được mong đợi.

Ví dụ :

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

Làm thế nào để trả lời câu hỏi này?
Không có thương hiệu Manchester

đây là ví dụ về loại trả lại khác nhau.
Parth
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.