重写方法是否可以使用不同的返回类型?
答案 0 :(得分:153)
Java支持覆盖方法的 * 协变返回类型。这意味着重写的方法可能具有更多特定的返回类型。也就是说,只要新的返回类型可以分配给您覆盖的方法的返回类型,就允许它。
例如:
class ShapeBuilder {
...
public Shape build() {
....
}
class CircleBuilder extends ShapeBuilder{
...
@Override
public Circle build() {
....
}
这在section 8.4.5 of the Java Language Specification中指定:
如果返回类型是引用类型,则返回类型可能会因覆盖彼此的方法而异。 return-type-substitutability的概念支持协变返回,即返回类型到子类型的特化。
当且仅当满足以下条件时,具有返回类型R1的方法声明d1是具有返回类型R2的另一个方法d2的return-type-substitutable:
如果R1无效,则R2无效。
如果R1是基本类型,则R2与R1相同。
如果R1是参考类型,则:
R1是R2的子类型,或者R1可以通过未经检查的转换(第5.1.9节)转换为R2的子类型,或
R1 = | R2 |
(“| R2 |”指的是R2的擦除,如§4.6 of the JLS中所定义。)
*在Java 5之前,Java具有不变返回类型,这意味着需要方法覆盖的返回类型才能与被覆盖的方法完全匹配。
答案 1 :(得分:20)
是的,它可能有所不同,但它们有一些限制。
在Java 5.0之前,当您重写方法时,参数和返回类型必须完全匹配。在Java 5.0中,它引入了一个名为协变返回类型的新工具。您可以使用相同的签名覆盖方法,但返回返回的对象的子类。换句话说,子类中的方法可以返回一个对象,该对象的类型是方法返回的类型的子类,在超类中具有相同的签名。
答案 2 :(得分:18)
是的,如果他们返回一个子类型。这是一个例子:
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 {
}
}
此代码编译并运行。
答案 3 :(得分:7)
一般来说,返回类型的覆盖方法可能不同。但它并非直截了当,其中涉及到一些案例。
案例1:如果返回类型是原始数据类型或无效。
输出:如果返回类型为void或primitive,则父类方法和重写方法的数据类型应相同。 例如如果返回类型是int,float,string那么它应该是相同的
案例2:如果返回类型是派生数据类型:
输出:如果父类方法的返回类型是派生类型,则重写方法的返回类型是派生数据类型的子类的派生数据类型。 例如假设我有A级 B是A的子类 C是B的子类 D是C的子类 那么如果超类返回类型A那么重写方法是子类可以返回A,B,C或D类型,即它的子类型。这也称为协变。
答案 4 :(得分:5)
是可能..只有当父类方法返回类型为
时,返回类型才可以不同
超类型的子类方法返回类型..
意味着
class ParentClass {
public Circle() method1() {
return new Cirlce();
}
}
class ChildClass extends ParentClass {
public Square method1() {
return new Square();
}
}
Class Cirlce {
}
class Square extends Circle {
}
---
如果是,那么可以允许不同的返回类型......
答案 5 :(得分:2)
返回类型必须与声明的返回类型相同或者是子类型 在超类中的原始重写方法中。
答案 6 :(得分:2)
覆盖和返回类型以及协变返回
子类必须定义一个与继承版本完全匹配的方法。或者,从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分钟前
答案 7 :(得分:1)
是的,可以
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();
}
}
答案 8 :(得分:0)
其他答案都是正确的,但令人惊讶的是,所有这些都忽略了理论方面:返回类型可能不同,但它们只能限制超类中使用的类型,因为{{ 3}}
这非常简单:当你有“客户端”代码调用某种方法时:
int foo = someBar.bar();
然后上面必须工作(并且无论调用int
的哪个实现都返回bar()
的内容。
含义:如果有一个Bar子类覆盖bar()
,那么你仍然必须返回一些不会破坏“调用者代码”的东西。
换句话说:假设基础bar()
应该返回int。然后一个子类可以返回short
- 但不是long
,因为调用者可以处理short
值,但不能处理long
!
答案 9 :(得分: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
}
}
答案 10 :(得分:0)
是的,我们可以拥有!协变返回类型是常见示例之一
答案 11 :(得分:0)
好吧,答案是肯定的。
取决于问题。这里的每个人都对Java> = 5进行了回答,有人提到Java <5不具有协变量返回类型。
实际上,Java语言规范> = 5支持它,但是Java运行时不支持。特别是,JVM没有更新为支持协变返回类型。
在当时被视为“明智”的举动,但最终成为Java历史上最糟糕的设计决策之一,Java 5实现了许多新语言功能,而根本没有修改JVM或类文件规范。取而代之的是,所有功能都通过javac中的诡计实现:编译器为嵌套/内部类生成/使用普通类,为泛型类型进行类型擦除和强制转换,为嵌套/内部类私有“友谊”提供综合访问器,为外部“ this”提供综合实例字段指针,'。class'文字的合成静态字段等,等等。
和协变返回类型是javac添加的更多语法糖。
例如,在编译时:
class Base {
Object get() { return null; }
}
class Derived extends Base {
@Override
@SomeAnnotation
Integer get() { return null; }
}
javac将在Derived类中输出两个get方法:
Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }
生成的桥接方法(在字节码中标记为synthetic
和bridge
)实际上是覆盖Object:Base:get()
的原因,因为对于JVM,具有不同返回类型的方法是完全独立的,并且不能覆盖每个方法其他。为了提供预期的行为,网桥仅调用您的“真实”方法。在上面的示例中,javac将使用@SomeAnnotation对Derived中的bridge和real方法进行注释。
请注意,您无法在Java <5中手动编写此解决方案的代码,因为bridge和real方法仅在返回类型上有所不同,因此它们不能共存于Java程序中。但是在JVM领域,方法返回类型是方法签名的一部分(就像它们的参数一样),因此由于相同的返回类型不同,JVM仍将两个名称相同且采用相同参数的方法视为完全独立,并且可以共存。
(顺便说一句,字段的类型类似地是字节码中字段签名的一部分,因此合法的是,在单个字节码类中具有多个不同类型的字段,但名称相同。)
所以要完全回答您的问题:JVM不支持协变量返回类型,但是javac> = 5在编译时用甜美的语法糖对其进行了伪造。
答案 12 :(得分: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();
}
}