Clase abstracta en Java


274

¿Qué es una "clase abstracta" en Java?


35
+1 Esta pregunta es tan básica y fundamental, es un clásico para SO. Me sorprende que no se haya preguntado aquí antes.
Yuval

66
-1 para el comentario de Clement (si pudiera); lmgtfy no es una respuesta útil. En cuanto a por qué, lea, por ejemplo, este meta.stackexchange.com/questions/5280/embrace-the-non-googlers
Jonik

26
@tuergeist. Es irrelevante si es fácil para Google, siempre y cuando no se haya preguntado en SO antes. Además, ¿quién dice que las preguntas para principiantes sobre lenguajes de programación no pertenecen a SO?
Jonik

12
Una cosa que me gusta de SO es que obtendrías una respuesta condensada, bien puesta y al punto sin ninguna de las BS habituales que se encuentran en el resto de la web ... Bueno, algo así de todos modos. +1 para la pregunta!
Anders Hansson el

1
¡No se supone que SO tenga la cola larga! J & J siquiera hablar de esto alrededor de podcast ... 56
kwutchak

Respuestas:


342

Una clase abstracta es una clase que no puede ser instanciada. Una clase abstracta se usa creando una subclase heredada que se puede instanciar. Una clase abstracta hace algunas cosas para la subclase de herencia:

  1. Defina los métodos que puede utilizar la subclase heredada.
  2. Defina métodos abstractos que la subclase heredada debe implementar.
  3. Proporcione una interfaz común que permita intercambiar la subclase con todas las demás subclases.

Aquí hay un ejemplo:

abstract public class AbstractClass
{
    abstract public void abstractMethod();
    public void implementedMethod() { System.out.print("implementedMethod()"); }
    final public void finalMethod() { System.out.print("finalMethod()"); }
}

Tenga en cuenta que "abstractMethod ()" no tiene ningún cuerpo de método. Debido a esto, no puede hacer lo siguiente:

public class ImplementingClass extends AbstractClass
{
    // ERROR!
}

¡No hay ningún método que implemente abstractMethod()! Por lo tanto, no hay forma de que la JVM sepa qué se supone que debe hacer cuando algo así sucede new ImplementingClass().abstractMethod().

Aquí hay una correcta ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
}

Tenga en cuenta que no tiene que definir implementedMethod()o finalMethod(). Ya estaban definidos por AbstractClass.

Aquí hay otro correcto ImplementingClass.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

En este caso, lo ha anulado implementedMethod().

Sin embargo, debido a la finalpalabra clave, lo siguiente no es posible.

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
    public void finalMethod() { System.out.print("ERROR!"); }
}

No puede hacer esto porque la implementación de finalMethod()in AbstractClassestá marcada como la implementación final de finalMethod(): no se permitirán otras implementaciones, nunca.

Ahora se puede también aplicar una clase abstracta en dos ocasiones:

public class ImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("abstractMethod()"); }
    public void implementedMethod() { System.out.print("Overridden!"); }
}

// In a separate file.
public class SecondImplementingClass extends AbstractClass
{
    public void abstractMethod() { System.out.print("second abstractMethod()"); }
}

Ahora en algún lugar podrías escribir otro método.

public tryItOut()
{
    ImplementingClass a = new ImplementingClass();
    AbstractClass b = new ImplementingClass();

    a.abstractMethod();    // prints "abstractMethod()"
    a.implementedMethod(); // prints "Overridden!"     <-- same
    a.finalMethod();       // prints "finalMethod()"

    b.abstractMethod();    // prints "abstractMethod()"
    b.implementedMethod(); // prints "Overridden!"     <-- same
    b.finalMethod();       // prints "finalMethod()"

    SecondImplementingClass c = new SecondImplementingClass();
    AbstractClass d = new SecondImplementingClass();

    c.abstractMethod();    // prints "second abstractMethod()"
    c.implementedMethod(); // prints "implementedMethod()"
    c.finalMethod();       // prints "finalMethod()"

    d.abstractMethod();    // prints "second abstractMethod()"
    d.implementedMethod(); // prints "implementedMethod()"
    d.finalMethod();       // prints "finalMethod()"
}

Tenga en cuenta que aunque declaramos bun AbstractClasstipo, se muestra "Overriden!". Esto se debe a que el objeto que instanciamos era en realidad un ImplementingClass, que implementedMethod()por supuesto se anula. (Es posible que haya visto esto denominado polimorfismo).

Si deseamos acceder a un miembro específico de una subclase particular, primero debemos bajar a esa subclase:

// Say ImplementingClass also contains uniqueMethod()
// To access it, we use a cast to tell the runtime which type the object is
AbstractClass b = new ImplementingClass();
((ImplementingClass)b).uniqueMethod();

Por último, no puede hacer lo siguiente:

public class ImplementingClass extends AbstractClass, SomeOtherAbstractClass
{
    ... // implementation
}

Solo se puede extender una clase a la vez. Si necesita extender varias clases, deben ser interfaces. Puedes hacerlo:

public class ImplementingClass extends AbstractClass implements InterfaceA, InterfaceB
{
    ... // implementation
}

Aquí hay una interfaz de ejemplo:

interface InterfaceA
{
    void interfaceMethod();
}

Esto es básicamente lo mismo que:

abstract public class InterfaceA
{
    abstract public void interfaceMethod();
}

La única diferencia es que la segunda forma no le permite al compilador saber que en realidad es una interfaz. Esto puede ser útil si desea que las personas solo implementen su interfaz y no otras. Sin embargo, como regla general para principiantes, si su clase abstracta solo tiene métodos abstractos, probablemente debería convertirla en una interfaz.

Lo siguiente es ilegal:

interface InterfaceB
{
    void interfaceMethod() { System.out.print("ERROR!"); }
}

No puede implementar métodos en una interfaz. Esto significa que si implementa dos interfaces diferentes, los diferentes métodos en esas interfaces no pueden colisionar. Como todos los métodos en una interfaz son abstractos, debe implementar el método, y dado que su método es la única implementación en el árbol de herencia, el compilador sabe que tiene que usar su método.


55
@Imagist -1 para una descripción incorrecta de la declaración c.implementedMethod (); // imprime "implementMethod ()", imprimirá "Overriden!" siempre
Sachin Kumar

2
@Sachin Perdí media hora tyring para entender por qué iba a imprimir "implementMethod ()" y luego vi tu comentario. ¿Algo cambió con Java u otros simplemente pasaron por alto el error?
Rounak

@SachinKumar Debido a la falta de respuesta del autor, me he encargado de solucionar este error. CMIIW.
Mateen Ulhaq

@SachinKumar Llegué un poco tarde al juego aquí, pero ¿dirías que una buena analogía sería una declaración de método (pero ninguna implementación) en un archivo de encabezado C ++?
Schwaitz

55
@SachinKumar, ¿por qué c.implementedMethod()imprimiría "Overriden!" SecondImplementingClassno anula implementedMethod().
John Red

75

Una clase Java se vuelve abstracta bajo las siguientes condiciones:

1. Al menos uno de los métodos está marcado como abstracto:

public abstract void myMethod()

En ese caso, el compilador lo obliga a marcar toda la clase como abstracta.

2. La clase está marcada como abstracta:

abstract class MyClass

Como ya se dijo: si tiene un método abstracto, el compilador lo obliga a marcar toda la clase como abstracta. Pero incluso si no tiene ningún método abstracto, puede marcar la clase como abstracta.

Uso común:

Un uso común de las clases abstractas es proporcionar un esquema de una clase similar a como lo hace una interfaz. Pero a diferencia de una interfaz, ya puede proporcionar funcionalidad, es decir, algunas partes de la clase se implementan y algunas partes solo se describen con una declaración de método. ("resumen")

No se puede crear una instancia de una clase abstracta, pero puede crear una clase concreta basada en una clase abstracta, que luego se puede instanciar. Para hacerlo, debe heredar de la clase abstracta y anular los métodos abstractos, es decir, implementarlos.


1
Nitpick: la segunda 'condición' es redundante, ya que solo puede declarar un método abstracto en una clase que se declara explícitamente como abstracto.
Stephen C

2
De acuerdo, el consejo no es realmente correcto, o está bien escrito, solo está bien formateado.
Mediodía Seda

Pero su consejo de "hacer una clase concreta" también está mal redactado. Usted no hace un hormigón de clase, ya sea es, o no es, dependiendo de si es o no abstracta.
Mediodía Seda

1
Esto esta simplemente mal. Una clase abstracta no tiene que tener ningún método abstracto. Puede hacer una clase abstracta sin métodos, o solo con métodos concretos.
Jorn

1
10 años tarde al juego, pero esta es la respuesta más precisa. @Jorn estás confundido con la respuesta, creo. Estoy seguro de que está implícito que la abstractpalabra clave es todo lo que se necesita para que una clase sea abstracta. Pero una clase concreta no puede contener un abstract método . Por lo tanto, si su clase tiene un abstractmétodo, debe declararse como una abstractclase para el compilador.
Rakib

24

Una clase que se declara usando la palabra clave abstracta se conoce como abstract class. La abstracción es un proceso de ocultar los detalles de implementación de datos y mostrar solo la funcionalidad al usuario. La abstracción te permite concentrarte en lo que hace el objeto en lugar de cómo lo hace.

Cosas principales de la clase abstracta

  • Una clase abstracta puede o no contener métodos abstractos. Puede haber métodos no abstractos.

    Un método abstracto es un método que se declara sin una implementación (sin llaves y seguido de un punto y coma), como este:

    ex: abstract void moveTo(double deltaX, double deltaY);

  • Si una clase tiene al menos un método abstracto, entonces esa clase debe ser abstracta

  • Las clases abstractas no se pueden instanciar (no está permitido crear objetos de la clase abstracta)

  • Para usar una clase abstracta, debes heredarla de otra clase. Proporcione implementaciones a todos los métodos abstractos que contiene.

  • Si hereda una clase abstracta, debe proporcionar implementaciones a todos los métodos abstractos que contiene.

Declarar clase abstracta La especificación de una abstractpalabra clave antes de la clase durante la declaración la hace abstracta. Echa un vistazo al siguiente código:

abstract class AbstractDemo{ }

Declarar método abstracto Especificar la abstractpalabra clave antes del método durante la declaración lo hace abstracto. Echa un vistazo al siguiente código,

abstract void moveTo();//no body

¿Por qué necesitamos abstraer clases?

En una aplicación de dibujo orientada a objetos, puede dibujar círculos, rectángulos, líneas, curvas de Bezier y muchos otros objetos gráficos. Todos estos objetos tienen ciertos estados (por ejemplo: posición, orientación, color de línea, color de relleno) y comportamientos (por ejemplo: mover, rotar, cambiar el tamaño, dibujar) en común. Algunos de estos estados y comportamientos son los mismos para todos los objetos gráficos (por ejemplo: color de relleno, posición y moveTo). Otros requieren una implementación diferente (por ejemplo: cambiar el tamaño o dibujar). Todos los objetos gráficos deben poder dibujar o cambiar su tamaño, solo difieren en cómo lo hacen.

Esta es una situación perfecta para una superclase abstracta. Puede aprovechar las similitudes y declarar todos los objetos gráficos para heredar del mismo objeto padre abstracto (por GraphicObjectejemplo:) como se muestra en la siguiente figura. ingrese la descripción de la imagen aquí

Primero, declara una clase abstracta GraphicObject, para proporcionar variables miembro y métodos que son totalmente compartidos por todas las subclases, como la posición actual y el método moveTo. GraphicObjecttambién declararon métodos abstractos, como dibujar o cambiar el tamaño, que deben implementarse en todas las subclases, pero deben implementarse de diferentes maneras. La GraphicObjectclase puede verse así:

abstract class GraphicObject {

  void moveTo(int x, int y) {
    // Inside this method we have to change the position of the graphic 
    // object according to x,y     
    // This is the same in every GraphicObject. Then we can implement here. 
  }

  abstract void draw(); // But every GraphicObject drawing case is 
                        // unique, not common. Then we have to create that 
                        // case inside each class. Then create these    
                        // methods as abstract 
  abstract void resize();
}

Uso del método abstracto en subclases Cada subclase no abstracta de GraphicObject, como Circley Rectangle, debe proporcionar implementaciones para los métodos drawy resize.

class Circle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here   
  }
}
class Rectangle extends GraphicObject {
  void draw() {
    //Add to some implementation here
  }
  void resize() {
    //Add to some implementation here
  }
}

Dentro del mainmétodo puede llamar a todos los métodos como este:

public static void main(String args[]){
   GraphicObject c = new Circle();
   c.draw();
   c.resize();
   c.moveTo(4,5);   
}

Formas de lograr la abstracción en Java

Hay dos formas de lograr la abstracción en java

  • Clase abstracta (0 a 100%)
  • Interfaz (100%)

Clase abstracta con constructores, miembros de datos, métodos, etc.

abstract class GraphicObject {

  GraphicObject (){
    System.out.println("GraphicObject  is created");
  }
  void moveTo(int y, int x) {
       System.out.println("Change position according to "+ x+ " and " + y);
  }
  abstract void draw();
}

class Circle extends GraphicObject {
  void draw() {
    System.out.println("Draw the Circle");
  }
}

class TestAbstract {  
 public static void main(String args[]){

   GraphicObject  grObj = new Circle ();
   grObj.draw();
   grObj.moveTo(4,6);
 }
}

Salida:

GraphicObject  is created
Draw the Circle
Change position according to 6 and 4

Recuerda dos reglas:

  • Si la clase tiene pocos métodos abstractos y pocos métodos concretos, declararla como una abstractclase.

  • Si la clase solo tiene métodos abstractos, declare como un interface.

Referencias


¿Por qué el orden de los parámetros x e y en moveTo es diferente en el ejemplo anterior, en el ejemplo siguiente y en la salida del ejemplo siguiente? Si estamos tratando de ilustrar la importancia de conceptos como interfaces y clases abstractas, ¿no deberíamos usar las mismas firmas de funciones que las interfaces o clases abstractas que estamos implementando o extendiendo de manera consistente?
Jonathan Rys

las dos reglas lo
delatan

4

Es una clase que no se puede instanciar, y obliga a implementar clases para, posiblemente, implementar métodos abstractos que describe.


3

Simplemente hablando, puedes pensar en una clase abstracta como una interfaz con un poco más de capacidades.

No se puede crear una instancia de una interfaz, que también es válida para una clase abstracta.

En su interfaz, puede definir los encabezados de los métodos y TODOS los implementadores están obligados a implementarlos todos . En una clase abstracta también puede definir los encabezados de sus métodos, pero aquí, a diferencia de la interfaz, también puede definir el cuerpo (generalmente una implementación predeterminada) del método. Además, cuando otras clases se extienden (nota, no implementar y, por lo tanto, también puede tener una sola clase abstracta por clase secundaria) su clase abstracta, no están obligados a implementar todos sus métodos de su clase abstracta, a menos que especifique un método abstracto ( en tal caso funciona como para interfaces, no puede definir el cuerpo del método).

public abstract class MyAbstractClass{
  public abstract void DoSomething();
}

De lo contrario, para los métodos normales de una clase abstracta, los "herederos" pueden usar el comportamiento predeterminado o anularlo, como de costumbre.

Ejemplo:

public abstract class MyAbstractClass{

  public int CalculateCost(int amount){
     //do some default calculations
     //this can be overriden by subclasses if needed
  }

  //this MUST be implemented by subclasses
  public abstract void DoSomething();
}

Esta respuesta no es útil si el OP no sabe qué es una interfaz. Dado que las clases y las interfaces abstractas están interrelacionadas, es muy poco probable que el OP conozca una sin conocer la otra.
Imagist

Pero podría ser. Puede ser que solo sepa qué es una interfaz y cómo funciona, y luego se encuentra con clases abstractas y se pregunta por qué uno debería necesitarlas. ¿No podría ser eso?
Juri

3

De la documentación de Oracle

Métodos abstractos y clases:

Una clase abstracta es una clase que se declara abstracta; puede incluir o no métodos abstractos.

Las clases abstractas no se pueden instanciar, pero se pueden subclasificar

Un método abstracto es un método que se declara sin una implementación (sin llaves y seguido de un punto y coma), como este:

abstract void moveTo(double deltaX, double deltaY);

Si una clase incluye métodos abstractos, entonces la clase misma debe declararse abstracta, como en:

public abstract class GraphicObject {
   // declare fields
   // declare nonabstract methods
   abstract void draw();
}

Cuando una clase abstracta se subclasifica, la subclase generalmente proporciona implementaciones para todos los métodos abstractos en su clase padre. Sin embargo, si no es así, entonces la subclase también debe declararse abstracta .

Dado abstract classesy interfacesestán relacionados, echa un vistazo a continuación preguntas SE:

¿Cuál es la diferencia entre una interfaz y una clase abstracta?

¿Cómo debería haber explicado la diferencia entre una interfaz y una clase abstracta?


3

Obtenga sus respuestas aquí:

Clase abstracta vs interfaz en Java

¿Puede una clase abstracta tener un método final?

Por cierto, esas son preguntas que hizo recientemente. Piensa en una nueva pregunta para construir reputación ...

Editar:

Acabo de darme cuenta de que los carteles de esta y las preguntas a las que se hace referencia tienen el mismo nombre o al menos un nombre similar, pero el ID de usuario siempre es diferente. Entonces, o bien, hay un problema técnico, que Keyur tiene problemas para iniciar sesión nuevamente y encontrar las respuestas a sus preguntas o este es un tipo de juego para entretener a la comunidad SO;)


Y es por eso que verifiqué 'wiki de la comunidad': uno no debería aumentar la represalia al reaccionar ante esas preguntas;)
Andreas Dolk el

1

Poca adición a todas estas publicaciones.

A veces es posible que desee declarar una clase y, sin embargo, no saber cómo definir todos los métodos que pertenecen a esa clase. Por ejemplo, es posible que desee declarar una clase llamada Writer e incluir en ella un método miembro llamado write () . Sin embargo, no sabe cómo codificar write () porque es diferente para cada tipo de dispositivo Writer. Por supuesto, planea manejar esto derivando una subclase de Writer, como Impresora, Disco, Red y Consola.


1

Una clase abstracta no puede ser instanciada directamente, sino que debe derivarse para ser utilizable. Una clase DEBE ser abstracta si contiene métodos abstractos: ya sea directamente

abstract class Foo {
    abstract void someMethod();
}

o indirectamente

interface IFoo {
    void someMethod();
}

abstract class Foo2 implements IFoo {
}

Sin embargo, una clase puede ser abstracta sin contener métodos abstractos. Es una forma de prevenir la instantación directa, p. Ej.

abstract class Foo3 {
}

class Bar extends Foo3 {

}

Foo3 myVar = new Foo3(); // illegal! class is abstract
Foo3 myVar = new Bar(); // allowed!

El último estilo de clases abstractas se puede utilizar para crear clases "tipo interfaz". A diferencia de las interfaces, una clase abstracta puede contener métodos no abstractos y variables de instancia. Puede usar esto para proporcionar alguna funcionalidad básica para extender las clases.

Otro patrón frecuente es implementar la funcionalidad principal en la clase abstracta y definir parte del algoritmo en un método abstracto para ser implementado por una clase extendida. Estúpido ejemplo:

abstract class Processor {
    protected abstract int[] filterInput(int[] unfiltered);

    public int process(int[] values) {
        int[] filtered = filterInput(values);
        // do something with filtered input
    }
}

class EvenValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove odd numbers
    }
}

class OddValues extends Processor {
    protected int[] filterInput(int[] unfiltered) {
        // remove even numbers
    }
}

1

Solución - clase base (resumen)

public abstract class Place {

String Name;
String Postcode;
String County;
String Area;

Place () {

        }

public static Place make(String Incoming) {
        if (Incoming.length() < 61) return (null);

        String Name = (Incoming.substring(4,26)).trim();
        String County = (Incoming.substring(27,48)).trim();
        String Postcode = (Incoming.substring(48,61)).trim();
        String Area = (Incoming.substring(61)).trim();

        Place created;
        if (Name.equalsIgnoreCase(Area)) {
                created = new Area(Area,County,Postcode);
        } else {
                created = new District(Name,County,Postcode,Area);
        }
        return (created);
        }

public String getName() {
        return (Name);
        }

public String getPostcode() {
        return (Postcode);
        }

public String getCounty() {
        return (County);
        }

public abstract String getArea();

}

1
intente formatear todo el código como código, y agregue alguna explicación, en este momento esto difícilmente puede considerarse una respuesta.
NomeN

3
hasta y a menos que no haya dado una explicación de su código. Serías considerado como un mal contestador. Así que por favor dé una explicación aquí
devsda

0

Una clase abstracta es una clase que se declara abstracta; puede incluir o no métodos abstractos. Las clases abstractas no pueden instanciarse, pero pueden subclasificarse.

En otras palabras, una clase que se declara con una palabra clave abstracta se conoce como clase abstracta en java. Puede tener métodos abstractos (método sin cuerpo) y no abstractos (método con cuerpo).

Nota importante: - Las clases abstractas no se pueden usar para crear instancias de objetos, se pueden usar para crear referencias de objetos, porque el enfoque de Java para el polimorfismo en tiempo de ejecución se implementa mediante el uso de referencias de superclase. Por lo tanto, debe ser posible crear una referencia a una clase abstracta para que pueda usarse para apuntar a un objeto de subclase. Verá esta función en el ejemplo a continuación.

abstract class Bike{  
  abstract void run();  
}  

class Honda4 extends Bike{  
    void run(){
        System.out.println("running safely..");
    }  

    public static void main(String args[]){  
       Bike obj = new Honda4();  
       obj.run();  
    }  
} 

0

Una clase abstracta es aquella que no está completamente implementada, pero proporciona una especie de plano para las subclases. Puede implementarse parcialmente porque contiene métodos concretos completamente definidos, pero también puede contener métodos abstractos. Estos son métodos con firma pero sin cuerpo de método. Cualquier subclase debe definir un cuerpo para cada método abstracto; de lo contrario, también debe declararse abstracto. Debido a que las clases abstractas no pueden ser instanciadas, deben ser extendidas por al menos una subclase para ser utilizadas. Piense en la clase abstracta como la clase genérica, y las subclases están ahí para completar la información que falta.


0

Clase que puede tener métodos tanto concretos como no concretos, es decir, con y sin cuerpo.

  1. Los métodos sin implementación deben contener una palabra clave 'abstracta'.
  2. La clase abstracta no puede ser instanciada.

-1

No hace nada, solo proporciona una plantilla común que se compartirá para su subclase

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.