2008-10-13 12 views
99

Algo curioso sucede en Java cuando utiliza una clase abstracta para implementar una interfaz: algunos de los métodos de la interfaz pueden faltar por completo (es decir, no existe una declaración abstracta o una implementación real), pero el compilador no se queja.¿Por qué una clase abstracta que implementa una interfaz puede perder la declaración/implementación de uno de los métodos de la interfaz?

Por ejemplo, dada la interfaz:

public interface IAnything { 
    void m1(); 
    void m2(); 
    void m3(); 
} 

la siguiente clase abstracta consigue alegremente compilado sin una advertencia o un error:

public abstract class AbstractThing implements IAnything { 
    public void m1() {} 
    public void m3() {} 
} 

¿Puede explicar por qué?

+0

No se puede crear un objeto de una clase abstracta. Entonces, mientras no se proporcione una implementación para una clase abstracta, no se pueden crear objetos para IAnything. Así que esto está absolutamente bien para el compilador. El compilador espera que cualquier clase no abstracta que implemente IAnything debe implementar todos los métodos declarados de IAnything. Y como uno tiene que extender e implementar AbstractThing para poder crear objetos, el compilador arrojará un error, si esa implementación no implementa los métodos de IAnything que haya quedado fuera de AbstractThing. – VanagaS

+0

¿PODEMOS LLAMAR ESO un "patrón de diseño del adaptador"? si mantuvimos m1, m2, m3 cuerpo vacío en clase abstracta. luego MyMainClass amplía esa clase abstracta y yo podría anular el método que desee, sin obligación de anular todos los métodos. ¡Por favor, avise! –

Respuesta

130

Eso es porque si una clase es abstracta, entonces, por definición, se le requiere para crear subclases de la misma para crear una instancia. Las subclases serán requeridas (por el compilador) para implementar cualquier método de interfaz que la clase abstracta omitió.

Siguiendo su código de ejemplo, intente crear una subclase de AbstractThing sin implementar el método m2 y vea qué errores le proporciona el compilador. Te obligará a implementar este método.

+0

Creo que el compilador aún debe emitir advertencias sobre las clases abstractas que implementan las interfaces de forma incompleta, simplemente porque entonces necesita ir a través de 2 definiciones de clase en lugar de 1 para ver lo que necesita en una subclase. Sin embargo, esta es una limitación de lenguaje/compilador. – workmad3

+3

No sería una buena idea, ya que normalmente puede haber muchas clases abstractas y las advertencias "falsas" pronto te abrumarían, haciendo que pierdas las advertencias "verdaderas". Si lo piensas bien, la palabra clave 'abstracta' está allí específicamente para decirle al compilador que suprima las advertencias para esa clase. – belugabob

+4

@workmad - si tiene implementaciones comunes para un subconjunto de métodos de interfaz, tiene más sentido clasificarlo en una clase base separada (DRY triunfa sobre el código de un solo lugar) – Gishu

30

Perfectamente bien.
No se pueden crear instancias de clases abstractas ... pero las clases abstractas se pueden usar para alojar implementaciones comunes para m1() y m3().
Así que si m2() aplicación es diferente para cada aplicación, pero M1 y M3 no lo son. Podría crear diferentes implementaciones concretas de IAnything con solo la implementación de diferentes m2 y derivarse de AbstractThing, respetando el principio DRY. Validar si la interfaz está completamente implementada para una clase abstracta es inútil ..

Actualización: Curiosamente, me parece que C# impone esto como un error de compilación. Usted está obligado a copiar las firmas de los métodos y el prefijo con 'public abstract' en la clase base abstracta en este escenario .. (algo nuevo cada día :)

1

Las clases abstractas no son necesarios para implementar los métodos. Entonces, aunque implementa una interfaz, los métodos abstractos de la interfaz pueden permanecer abstractos. Si intenta implementar una interfaz en una clase concreta (es decir, no es abstracta) y no implementa los métodos abstractos que el compilador le dirá: implemente los métodos abstractos o declare la clase como abstracta.

2

Interfaz significa una clase que no tiene implementada su método, pero con una declaración justa.
Otra mano, clase abstracta es una clase que puede tener implementación de algún método junto con algún método con declaración justa, sin implementación.
Cuando implementamos una interfaz a una clase abstracta, significa que la clase abstracta heredó todos los métodos de la interfaz. Como, no es importante implementar todo el método en la clase abstracta, sin embargo, se trata de una clase abstracta (también por herencia), por lo que la clase abstracta puede dejar parte del método en la interfaz sin implementación aquí. Pero, cuando esta clase abstracta será heredada por alguna clase concreta, deberán implementar todos los métodos no implementados allí en la clase abstracta.

5

Eso está bien. Para entender lo anterior, primero debes entender la naturaleza de las clases abstractas. Son similares a las interfaces en ese sentido. Esto es lo que Oracle dice sobre esto here.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

Así que hay que pensar en qué sucede cuando una interfaz amplía otra interfaz. Por ejemplo ...

//Filename: Sports.java 
public interface Sports 
{ 
    public void setHomeTeam(String name); 
    public void setVisitingTeam(String name); 
} 

//Filename: Football.java 
public interface Football extends Sports 
{ 
    public void homeTeamScored(int points); 
    public void visitingTeamScored(int points); 
    public void endOfQuarter(int quarter); 
} 

... como puede ver, esto también compila perfectamente bien. Simplemente porque, al igual que una clase abstracta, una interfaz NO se puede crear instancias. Por lo tanto, no es necesario mencionar explícitamente los métodos de su "padre". Sin embargo, TODAS las firmas de métodos principales DO se convierten implícitamente en parte de la interfaz extendida o la implementación de la clase abstracta. Entonces, una vez que una clase apropiada (una que puede ser instanciada) amplía lo anterior, será necesario asegurar que cada método abstracto sea implementado.

Espero que ayude ... y Allahu 'alam!

+0

Ese es un punto de vista interesante. Me hace pensar que las "clases abstractas" son realmente "interfaces concretas", es decir, interfaces con algunos métodos concretos, en lugar de clases con algunos métodos abstractos. –

+0

... un poco de ambos realmente. Pero una cosa es segura, no son instanciables. – Grateful

2

When an Abstract Class Implements an Interface

In the section on Interfaces, it was noted that a class that implements an interface must implement all of the interface's methods. It is possible, however, to define a class that does not implement all of the interface's methods, provided that the class is declared to be abstract. For example,

abstract class X implements Y { 
    // implements all but one method of Y 
} 

class XX extends X { 
    // implements the remaining method in Y 
} 

In this case, class X must be abstract because it does not fully implement Y, but class XX does, in fact, implement Y.

Referencia: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

1

Dada la interfaz:

public interface IAnything { 
    int i; 
    void m1(); 
    void m2(); 
    void m3(); 
} 

Este es ho w Java en realidad lo ve:

public interface IAnything { 
    public static final int i; 
    public abstract void m1(); 
    public abstract void m2(); 
    public abstract void m3(); 
} 

lo que puede dejar algunos (o todos) de estos métodos abstract sin aplicarse, al igual que lo haría en el caso de las clases que se extienden abstract otra clase abstract.

Cuando implement un interface, la regla de que todos los interface métodos deben ser implementadas en el class derivada, sólo se aplica al concreto class aplicación (es decir, que no es en sí abstract).

Si efectivamente planea en la creación de un abstract class fuera de él, entonces no hay ninguna regla que diga que ha de implement todos los métodos interface (tenga en cuenta que, en tal caso, es obligatorio declarar la class derivados como abstract)

+0

Usando 'javap IAnything.class' para generar el segundo fragmento de código. – sharhp

Cuestiones relacionadas