Respuestas:
Java admite * tipos de retorno covariantes para métodos anulados. Esto significa que un método anulado puede tener más tipo de retorno específico. Es decir, siempre que el nuevo tipo de retorno sea asignable al tipo de retorno del método que está anulando, está permitido.
Por ejemplo:
class ShapeBuilder {
...
public Shape build() {
....
}
class CircleBuilder extends ShapeBuilder{
...
@Override
public Circle build() {
....
}
Esto se especifica en la sección 8.4.5 de la Especificación del lenguaje Java :
Los tipos de retorno pueden variar entre los métodos que se anulan entre sí si los tipos de retorno son tipos de referencia. La noción de sustituibilidad de tipo de retorno admite retornos covariantes, es decir, la especialización del tipo de retorno a un subtipo.
Una declaración de método d1 con tipo de retorno R1 es sustituible por tipo de retorno por otro método d2 con tipo de retorno R2, si y solo si se cumplen las siguientes condiciones:
Si R1 es nulo, entonces R2 es nulo.
Si R1 es un tipo primitivo, R2 es idéntico a R1.
Si R1 es un tipo de referencia, entonces:
R1 es un subtipo de R2 o R1 se puede convertir en un subtipo de R2 mediante conversión sin marcar (§5.1.9), o
R1 = | R2 |
("| R2 |" se refiere a la eliminación de R2, como se define en §4.6 del JLS ).
* Antes de Java 5, Java tenía tipos de retorno invariables , lo que significaba que el tipo de retorno de una anulación de método necesitaba coincidir exactamente con el método que se anulaba.
Sí, puede diferir, pero hay algunas limitaciones.
Antes de Java 5.0, cuando anula un método, ambos parámetros y el tipo de retorno deben coincidir exactamente. En Java 5.0, introduce una nueva instalación llamada tipo de retorno covariante. Puede anular un método con la misma firma pero devuelve una subclase del objeto devuelto. En otras palabras, un método en una subclase puede devolver un objeto cuyo tipo es una subclase del tipo devuelto por el método con la misma firma en la superclase.
Sí, si devuelven un subtipo. Aquí hay un ejemplo:
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 {
}
}
Este código se compila y se ejecuta.
En términos generales, sí, el tipo de retorno del método de anulación puede ser diferente. Pero no es sencillo, ya que hay algunos casos involucrados en esto.
Caso 1: si el tipo de retorno es un tipo de datos primitivo o nulo.
Salida: si el tipo de retorno es nulo o primitivo, el tipo de datos del método de clase principal y el método de anulación deberían ser los mismos. por ejemplo, si el tipo de retorno es int, float, string, entonces debería ser el mismo
Caso 2: si el tipo de retorno es un tipo de datos derivado:
Salida: si el tipo de retorno del método de la clase principal es el tipo derivado, entonces el tipo de retorno del método de anulación es el mismo tipo de datos derivados de la subclase al tipo de datos derivados. por ejemplo, supongamos que tengo una clase A, B es una subclase de A, C es una subclase de B y D es una subclase de C; entonces, si la superclase devuelve el tipo A, entonces el método de anulación es la subclase puede devolver el tipo A, B, C o D, es decir, sus subtipos. Esto también se llama covarianza.
sí Es posible ... el tipo de retorno puede ser diferente solo si el tipo de retorno del método de la clase primaria es
un supertipo del tipo de retorno del método de la clase secundaria ...
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 {
}
Bueno, la respuesta es si o no.
Depende de la pregunta. todos aquí respondieron con respecto a Java> = 5, y algunos mencionaron que Java <5 no presenta tipos de retorno covariantes.
en realidad, la especificación del lenguaje Java> = 5 lo admite, pero el tiempo de ejecución de Java no. en particular, la JVM no se actualizó para admitir tipos de retorno covariantes.
En lo que se vio entonces como un movimiento "inteligente", pero terminó siendo una de las peores decisiones de diseño en la historia de Java, Java 5 implementó un montón de nuevas características de lenguaje sin modificar la JVM o la especificación del archivo de clase. en su lugar, todas las características se implementaron con trucos en javac: el compilador genera / usa clases simples para clases anidadas / internas, borrado de tipos y moldes para genéricos, accesores sintéticos para "amistad" privada anidada / interna, campos de instancia sintéticos para "esto" externo punteros, campos estáticos sintéticos para literales '.class', etc., etc.
y los tipos de retorno covariante son aún más azúcar sintáctico agregado por javac.
por ejemplo, al compilar esto:
class Base {
Object get() { return null; }
}
class Derived extends Base {
@Override
@SomeAnnotation
Integer get() { return null; }
}
javac generará dos métodos get en la clase Derivada:
Integer Integer:Derived:get() { return null; }
synthetic bridge Object Object:Derived:get() { return Integer:Derived:get(); }
El método puente generado (marcado synthetic
y bridge
en código de bytes) es lo que realmente se anula Object:Base:get()
porque, para la JVM, los métodos con diferentes tipos de retorno son completamente independientes y no pueden anularse entre sí. Para proporcionar el comportamiento esperado, el puente simplemente llama a su método "real". en el ejemplo anterior, javac anotará métodos puente y reales en Derivado con @SomeAnnotation.
tenga en cuenta que no puede codificar manualmente esta solución en Java <5, porque los métodos bridge y real solo difieren en el tipo de retorno y, por lo tanto, no pueden coexistir en un programa Java. pero en el mundo de JVM, los tipos de retorno de métodos son parte de la firma del método (al igual que sus argumentos) y, por lo tanto, los dos métodos nombrados igual y tomando los mismos argumentos son considerados completamente independientes por la JVM debido a sus diferentes tipos de retorno, y puede coexistir
(Por cierto, los tipos de campos son igualmente parte de la firma del campo en bytecode, por lo que es legal tener varios campos de diferentes tipos pero con el mismo nombre dentro de una sola clase de bytecode).
para responder completamente a su pregunta: la JVM no admite tipos de retorno covariantes, pero javac> = 5 lo simula en tiempo de compilación con una capa de azúcar sintáctico dulce.
Anulación y tipos de retorno, y retornos covariantes
La subclase debe definir un método que coincida exactamente con la versión heredada. O, a partir de Java 5, puede cambiar el tipo de retorno en
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, este código se compilará. Si intentara compilar este código con un compilador 1.4 dirá que intenta usar un tipo de retorno incompatible - sandeep1987 hace 1 minuto
Las otras respuestas son todas correctas, pero sorprendentemente todas omiten el aspecto teórico aquí: los tipos de retorno pueden ser diferentes, pero solo pueden restringir el tipo utilizado en la superclase debido al Principio de sustitución de Liskov .
Es súper simple: cuando tienes un código de "cliente" que llama a algún método:
int foo = someBar.bar();
entonces lo anterior tiene que funcionar (y devolver algo que es un int
no importa qué implementación bar()
se invoque).
Significado: si hay una subclase de Bar que anula, bar()
entonces todavía tiene que devolver algo que no rompa el "código de llamada".
En otras palabras: suponga que se supone que la base bar()
debe devolver int. Entonces, una subclase podría regresar short
, pero no long
porque las personas que llamen estarán bien tratando con un short
valor, ¡pero no con un long
!
El tipo de retorno debe ser el mismo o un subtipo del tipo de retorno declarado en el método anulado original en la superclase.
SÍ, puede ser posible
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();
}
}
Si. Es posible que los métodos anulados tengan un tipo de retorno diferente.
Pero las limitaciones son que el método reemplazado debe tener un tipo de retorno que sea un tipo más específico del tipo de retorno del método real.
Todas las respuestas han dado ejemplos del método reemplazado para tener un tipo de retorno que es una subclase del tipo de retorno del método real.
Por ejemplo :
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
}
}
Pero esto no solo se limita a la subclase. Incluso las clases que implementan una interfaz son un tipo específico de la interfaz y, por lo tanto, pueden ser un tipo de retorno donde se espera que la interfaz.
Por ejemplo :
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
}
}
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();
}
}
error: method() in subclass cannot override method() in superclass