JavaRush /Blog Java /Random-ES /Diferencia entre clases abstractas e interfaces.

Diferencia entre clases abstractas e interfaces.

Publicado en el grupo Random-ES
¡Hola! En esta conferencia hablaremos sobre en qué se diferencian las clases abstractas de las interfaces y veremos ejemplos con clases abstractas comunes. Diferencia entre clases abstractas e interfaces - 1Dedicamos una conferencia separada a las diferencias entre una clase abstracta y una interfaz, ya que el tema es muy importante. Te preguntarán sobre la diferencia entre estos conceptos en el 90% de futuras entrevistas. Por lo tanto, asegúrese de comprender lo que lee y, si no comprende algo completamente, lea fuentes adicionales. Entonces, sabemos qué es una clase abstracta y qué es una interfaz. Ahora repasemos sus diferencias.
  1. Una interfaz solo describe el comportamiento. No tiene fortuna. Pero una clase abstracta tiene un estado: describe ambos.

    Tomemos una clase abstracta Birdy una interfaz como ejemplo Flyable:

    public abstract class Bird {
       private String species;
       private int age;
    
       public abstract void fly();
    
       public String getSpecies() {
           return species;
       }
    
       public void setSpecies(String species) {
           this.species = species;
       }
    
       public int getAge() {
           return age;
       }
    
       public void setAge(int age) {
           this.age = age;
       }
    }

    Creemos una clase de pájaro Mockingjay(sinsajo) y heredémosla de Bird:

    public class Mockingjay extends Bird {
    
       @Override
       public void fly() {
           System.out.println("¡Vuela, pajarito!");
       }
    
       public static void main(String[] args) {
    
           Mockingjay someBird = new Mockingjay();
           someBird.setAge(19);
           System.out.println(someBird.getAge());
       }
    }

    Como puede ver, podemos acceder fácilmente al estado de la clase abstracta: sus variables species(tipo) y age(edad).

    Pero si intentamos hacer lo mismo con la interfaz, la imagen será diferente. Podemos intentar agregarle variables:

    public interface Flyable {
    
       String species = new String();
       int age = 10;
    
       public void fly();
    }
    
    public interface Flyable {
    
       private String species = new String(); // error
       private int age = 10; // también un error
    
       public void fly();
    }

    Ni siquiera podremos crear variables privadas dentro de la interfaz. ¿Por qué? Porque el modificador privado se creó para ocultar la implementación al usuario. Pero no hay ninguna implementación dentro de la interfaz: no hay nada que ocultar allí.

    La interfaz solo describe el comportamiento. En consecuencia, no podremos implementar captadores y definidores dentro de la interfaz. Esa es la naturaleza de una interfaz: está destinada a tratar con el comportamiento, no con el estado.

    Java8 introdujo métodos de interfaz predeterminados que tienen una implementación. Ya los conoces, así que no los repetiremos.

  2. Una clase abstracta vincula y une clases que tienen una relación muy estrecha. Al mismo tiempo, la misma interfaz puede ser implementada por clases que no tienen nada en común.

    Volvamos a nuestro ejemplo con los pájaros.

    Nuestra clase abstracta Birdes necesaria para crear pájaros basándose en ella. ¡Solo pájaros y nadie más! Por supuesto que serán diferentes.

    Diferencia entre clases abstractas e interfaces - 2

    Con la interfaz Flyabletodo es diferente. Sólo describe el comportamiento correspondiente a su nombre: "volar". La definición de "volador", "capaz de volar" incluye muchos objetos que no están relacionados entre sí.

    Diferencia entre clases abstractas e interfaces - 3

    Estas 4 entidades no están relacionadas entre sí de ninguna manera. Qué puedo decir, ni siquiera todos están animados. Sin embargo, todos son Flyablecapaces de volar.

    No podríamos describirlos usando una clase abstracta. No tienen un estado común ni campos idénticos. Para caracterizar un avión, probablemente necesitaremos los campos “modelo”, “año de fabricación” y “número máximo de pasajeros”. Para Carlson, hay campos para todos los dulces que comió hoy y una lista de juegos que jugará con Kid. Para un mosquito... uh-uh... ni siquiera lo sabemos... ¿Tal vez “nivel de molestia”? :)

    Lo principal es que no podemos describirlos usando una clase abstracta. Son demasiado diferentes. Pero hay un comportamiento común: pueden volar. La interfaz es ideal para describir todo lo que hay en el mundo que puede volar, nadar, saltar o tener algún otro comportamiento.

  3. Las clases pueden implementar tantas interfaces como quieran, pero solo pueden heredar de una clase.

    Ya hemos hablado de esto más de una vez. No existe herencia múltiple en Java, pero sí implementación múltiple. Este punto se deriva en parte del anterior: una interfaz conecta muchas clases diferentes que a menudo no tienen nada en común, y se crea una clase abstracta para un grupo de clases que están muy cerca entre sí. Por lo tanto, es lógico que sólo puedas heredar de una de esas clases. Una clase abstracta describe la relación "es un".

Interfaces estándar de flujo de entrada y flujo de salida

Ya hemos repasado las distintas clases responsables de la transmisión de entrada y salida. Miremos InputStreamy OutputStream. En general, estas no son interfaces, sino clases abstractas reales. Ahora sabes qué son, por lo que trabajar con ellos será mucho más fácil :) InputStream- esta es una clase abstracta que es responsable de la entrada de bytes. Java tiene una serie de clases que heredan de InputStream. Cada uno de ellos está configurado para recibir datos de diferentes fuentes. Como InputStreames principal, proporciona varios métodos para trabajar cómodamente con flujos de datos. Cada niño tiene estos métodos InputStream:
  • int available()devuelve el número de bytes disponibles para lectura;
  • close()cierra la fuente de entrada;
  • int read()devuelve una representación entera del siguiente byte disponible en la secuencia. Si se llega al final de la transmisión, se devolverá el número -1;
  • int read(byte[] buffer)intenta leer bytes en un búfer, devolviendo el número de bytes leídos. Cuando llega al final del archivo, devuelve -1;
  • int read(byte[] buffer, int byteOffset, int byteCount)Lee parte de un bloque de bytes. Se utiliza cuando existe la posibilidad de que el bloque de datos no se haya llenado por completo. Cuando llega al final del archivo, devuelve -1;
  • long skip(long byteCount)salta byteCountun byte de entrada y devuelve el número de bytes ignorados.
Te aconsejo que estudies la lista completa de métodos . En realidad, hay más de una docena de clases sucesoras. Aquí están algunos ejemplos:
  1. FileInputStream: el tipo más común InputStream. Se utiliza para leer información de un archivo;
  2. StringBufferInputStream: otro tipo útil InputStream. Convierte una cadena en un flujo de datos de entrada InputStream;
  3. BufferedInputStream: flujo de entrada almacenado en búfer. Se utiliza con mayor frecuencia para mejorar la eficiencia.
¿Recuerdas cuando pasamos BufferedReadery dijimos que no teníamos que usarlo? Cuando escribimos:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))
... BufferedReaderno es necesario utilizarlo: InputStreamReaderhará el trabajo. Pero BufferedReaderlo hace de manera más eficiente y, además, puede leer datos en líneas enteras, en lugar de caracteres individuales. ¡ Todo BufferedInputStreames lo mismo! La clase acumula datos de entrada en un búfer especial sin acceder constantemente al dispositivo de entrada. Veamos un ejemplo:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;

public class BufferedInputExample {

   public static void main(String[] args) throws Exception {
       InputStream inputStream = null;
       BufferedInputStream buffer = null;

       try {

           inputStream = new FileInputStream("D:/Users/UserName/someFile.txt");

           buffer = new BufferedInputStream(inputStream);

           while(buffer.available()>0) {

               char c = (char)buffer.read();

               System.out.println("El personaje fue leído" + c);
           }
       } catch(Exception e) {

           e.printStackTrace();

       } finally {

           inputStream.close();
           buffer.close();
       }
   }
}
En este ejemplo, estamos leyendo datos de un archivo que se encuentra en la computadora en la dirección "D:/Users/UserName/someFile.txt" . Creamos 2 objetos FileInputStreamy BufferedInputStreamcomo su "envoltorio". Después de eso, leemos los bytes del archivo y los convertimos en caracteres. Y así sucesivamente hasta finalizar el archivo. Como puedes ver, aquí no hay nada complicado. Puede copiar este código y ejecutarlo en algún archivo real almacenado en su computadora :) Una clase OutputStreames una clase abstracta que define una salida de flujo de bytes. Como ya comprenderás, esta es la antípoda de InputStream'a. No es responsable de dónde leer los datos, sino de dónde enviarlos . Al igual que InputStream, esta clase abstracta proporciona a todos los descendientes un grupo de métodos para un trabajo conveniente:
  • int close()cierra el flujo de salida;
  • void flush()borra todos los buffers de salida;
  • abstract void write (int oneByte)escribe 1 byte en el flujo de salida;
  • void write (byte[] buffer)escribe una matriz de bytes en el flujo de salida;
  • void write (byte[] buffer, int offset, int count)escribe un rango de bytes de recuento de la matriz, comenzando en el desplazamiento de posición.
Estos son algunos de los descendientes de la clase OutputStream:
  1. DataOutputStream. Un flujo de salida que incluye métodos para escribir tipos de datos Java estándar.

    Una clase muy simple para escribir cadenas y tipos Java primitivos. Seguramente entenderás el código escrito incluso sin explicación:

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           DataOutputStream dos = new DataOutputStream(new FileOutputStream("testFile.txt"));
    
           dos.writeUTF("SomeString");
           dos.writeInt(22);
           dos.writeDouble(1.21323);
           dos.writeBoolean(true);
    
       }
    }

    Tiene métodos separados para cada tipo: writeDouble(), writeLong(), writeShort()etc.

  2. Clase FileOutputStream . Implementa un mecanismo para enviar datos a un archivo en el disco. Por cierto, ya lo usamos en el ejemplo anterior, ¿te diste cuenta? Lo pasamos dentro de DataOutputStream, que actuó como un "envoltorio".

  3. BufferedOutputStream. Flujo de salida almacenado en búfer. Tampoco nada complicado, la esencia es la misma que en BufferedInputStream(o BufferedReader'a). En lugar de la habitual grabación de datos secuencial, se utiliza la grabación a través de un búfer de "almacenamiento" especial. Al utilizar un búfer, puede reducir la cantidad de viajes de ida y vuelta al destino de los datos y, por lo tanto, mejorar la eficiencia.

    import java.io.*;
    
    public class DataOutputStreamExample {
    
       public static void main(String[] args) throws IOException {
    
           FileOutputStream outputStream = new FileOutputStream("D:/Users/Username/someFile.txt");
           BufferedOutputStream bufferedStream = new BufferedOutputStream(outputStream);
    
           String text = "I love Java!"; // convertiremos esta cadena en una matriz de bytes y la escribiremos en un archivo
    
           byte[] buffer = text.getBytes();
    
           bufferedStream.write(buffer, 0, buffer.length);
           bufferedStream.close();
       }
    }

    Nuevamente, puedes “jugar” con este código tú mismo y verificar cómo funcionará con archivos reales en tu computadora.

También puedes leer sobre los herederos en el material " Sistema InputStreamde entrada /salida ". Ah , y también tendremos una conferencia separada, por lo que habrá suficiente información sobre ellos para conocerlos por primera vez. ¡Eso es todo! Esperamos que comprenda bien las diferencias entre interfaces y clases abstractas y esté listo para responder cualquier pregunta, incluso una complicada :) OutputStreamFileInputStreamFileOutputStreamBufferedInputStream
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION