<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Java Magician]]></title><description><![CDATA[Tutoriales y cursos de programación en Java. Aprende a programar en Java desde cero.]]></description><link>https://javamagician.com/</link><image><url>https://javamagician.com/favicon.png</url><title>Java Magician</title><link>https://javamagician.com/</link></image><generator>Ghost 5.82</generator><lastBuildDate>Wed, 15 Apr 2026 22:45:39 GMT</lastBuildDate><atom:link href="https://javamagician.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Manejo de Excepciones en Java]]></title><description><![CDATA[En este tutorial, abordaremos los fundamentos del manejo de excepciones en Java, como usar try catch en Java, así como algunas de sus particularidades.]]></description><link>https://javamagician.com/java-manejo-excepciones/</link><guid isPermaLink="false">656f1e6c7f7643d09077e3cc</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Excepciones]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Sat, 16 Dec 2023 10:53:49 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/12/java-manejo-excepciones_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/12/java-manejo-excepciones_600x750.png" alt="Manejo de Excepciones en Java"><p>En este tutorial, abordaremos los fundamentos del manejo de excepciones en Java, as&#xED; como algunas de sus particularidades.</p>
<h2 id="span-name2-principios-basicosspan-2-principios-b%C3%A1sicos"><span name="2-principios-basicos"></span> <a href="#2-principios-basicos">2.</a> Principios B&#xE1;sicos</h2>
<h3 id="span-name2-1-que-esspan-21-%C2%BFqu%C3%A9-es"><span name="2-1-que-es"></span> <a href="#2-1-que-es">2.1.</a> &#xBF;Qu&#xE9; Es?</h3>
<p>Para comprender mejor las excepciones y el manejo de ellas, hagamos una comparaci&#xF3;n con la vida real.</p>
<p>Imagina que ordenamos un producto en l&#xED;nea, pero en el camino hay un problema en la entrega. Una buena empresa puede manejar este problema y redirigir elegantemente nuestro paquete para que a&#xFA;n llegue a tiempo.</p>
<p>De manera similar, en Java, el c&#xF3;digo puede experimentar errores mientras ejecuta nuestras instrucciones. Un buen manejo de excepciones puede manejar los errores y redirigir el programa de manera que el usuario a&#xFA;n tenga una experiencia positiva.</p>
<h3 id="span-name2-2-por-que-usarlospan-22-%C2%BFpor-qu%C3%A9-usarlo"><span name="2-2-por-que-usarlo"></span> <a href="#2-2-por-que-usarlo">2.2.</a> &#xBF;Por Qu&#xE9; Usarlo?</h3>
<p>Normalmente, escribimos c&#xF3;digo en un entorno idealizado: el sistema de archivos siempre contiene nuestros archivos, la red est&#xE1; saludable y la JVM siempre tiene suficiente memoria. A veces llamamos a esto el &quot;camino feliz&quot;.</p>
<p>Sin embargo, en producci&#xF3;n, los sistemas de archivos pueden corromperse, las redes pueden fallar y las JVM pueden quedarse sin memoria. El bienestar de nuestro c&#xF3;digo depende de c&#xF3;mo maneje los &quot;caminos infelices&quot;.</p>
<p>Debemos manejar estas condiciones porque afectan negativamente al flujo de la aplicaci&#xF3;n y generan excepciones:</p>
<pre><code class="language-java">public static List&lt;Jugador&gt; obtenerJugadores() throws IOException {
    Path ruta = Paths.get(&quot;jugadores.dat&quot;);
    List&lt;String&gt; jugadores = Files.readAllLines(ruta);

    return jugadores.stream()
      .map(Jugador::new)
      .collect(Collectors.toList());
}
</code></pre>
<p>Este c&#xF3;digo elige no manejar la <code>IOException</code>, sino pasarla hacia arriba en la pila de llamadas. En un entorno idealizado, el c&#xF3;digo funciona bien.</p>
<p>Pero, &#xBF;qu&#xE9; podr&#xED;a pasar en producci&#xF3;n si falta <code>jugadores.dat</code>?</p>
<pre><code>Exception in thread &quot;main&quot; java.nio.file.NoSuchFileException: players.dat &lt;-- players.dat file doesn&apos;t exist
    at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
    at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
    // ... m&#xE1;s traza de la pila
    at java.nio.file.Files.readAllLines(Unknown Source)
    at java.nio.file.Files.readAllLines(Unknown Source)
    at Excepciones.obtenerJugadores(Excepciones.java:12) &lt;-- La excepci&#xF3;n ocurre en el m&#xE9;todo obtenerJugadores(), en la l&#xED;nea 12
    at Excepciones.main(Excepciones.java:19) &lt;-- obtenerJugadores() es llamado por main(), en la l&#xED;nea 19
</code></pre>
<p><strong>Sin manejar esta excepci&#xF3;n, &#xA1;un programa por lo dem&#xE1;s saludable podr&#xED;a dejar de ejecutarse por completo!</strong> Necesitamos asegurarnos de que nuestro c&#xF3;digo tenga un plan para cuando las cosas salgan mal.</p>
<p>Tambi&#xE9;n cabe destacar otro beneficio aqu&#xED;, y es la propia traza de la pila. Gracias a esta traza, a menudo podemos identificar el c&#xF3;digo ofensor sin necesidad de utilizar un depurador.</p>
<h2 id="span-name3-jerarquia-de-excepcionesspan-3-jerarqu%C3%ADa-de-excepciones"><span name="3-jerarquia-de-excepciones"></span> <a href="#3-jerarquia-de-excepciones">3.</a> Jerarqu&#xED;a de Excepciones</h2>
<p>En &#xFA;ltima instancia, las excepciones son simplemente objetos de Java, y todas ellas extienden de <code>Throwable</code>:</p>
<p><img src="https://javamagician.com/content/images/2023/12/exceptions.png" alt="Manejo de Excepciones en Java" loading="lazy"></p>
<p>Hay tres categor&#xED;as principales de condiciones excepcionales:</p>
<ul>
<li>Excepciones verificadas</li>
<li>Excepciones no verificadas / Excepciones en tiempo de ejecuci&#xF3;n</li>
<li>Errores</li>
</ul>
<p><strong>Las excepciones en tiempo de ejecuci&#xF3;n y las excepciones no verificadas se refieren a lo mismo y a menudo se pueden usar de manera intercambiable.</strong></p>
<h3 id="span-name3-1-excepciones-verificadasspan-31-excepciones-verificadas"><span name="3-1-excepciones-verificadas"></span> <a href="#3-1-excepciones-verificadas">3.1.</a> Excepciones Verificadas</h3>
<p>Las excepciones verificadas son excepciones que el compilador de Java nos exige manejar. Debemos o bien declarar expl&#xED;citamente que lanzaremos la excepci&#xF3;n hacia arriba en la pila de llamadas, o debemos manejarla nosotros mismos. Hablaremos m&#xE1;s sobre ambos en un momento.</p>
<p><a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html?ref=javamagician.com">La documentaci&#xF3;n de Oracle</a> nos dice que debemos usar excepciones verificadas cuando razonablemente esperamos que el llamante de nuestro m&#xE9;todo pueda recuperarse.</p>
<p>Algunos ejemplos de excepciones verificadas son <code>IOException</code> y <code>ServletException</code>.</p>
<h3 id="span-name3-2-excepciones-no-verificadasspan-32-excepciones-no-verificadas"><span name="3-2-excepciones-no-verificadas"></span> <a href="#3-2-excepciones-no-verificadas">3.2.</a> Excepciones No Verificadas</h3>
<p>Las excepciones no verificadas son excepciones que el compilador de Java no nos exige manejar.</p>
<p>En pocas palabras, si creamos una excepci&#xF3;n que extiende de <code>RuntimeException</code>, ser&#xE1; no verificada; de lo contrario, ser&#xE1; verificada.</p>
<p>Y aunque esto suena conveniente, la documentaci&#xF3;n de Oracle nos dice que hay buenas razones para ambos conceptos, como diferenciar entre un error situacional (verificado) y un error de uso (no verificado).</p>
<p>Algunos ejemplos de excepciones no verificadas son <code>NullPointerException</code>, <code>IllegalArgumentException</code> y <code>SecurityException</code>.</p>
<h3 id="span-name3-3-erroresspan-33-errores"><span name="3-3-errores"></span> <a href="#3-3-errores">3.3.</a> Errores</h3>
<p>Los errores representan condiciones graves y generalmente irreparables, como una incompatibilidad de biblioteca, una recursi&#xF3;n infinita o fugas de memoria.</p>
<p>Y aunque no extienden <code>RuntimeException</code>, tambi&#xE9;n son no verificados.</p>
<p>En la mayor&#xED;a de los casos, ser&#xED;a extra&#xF1;o que manej&#xE1;ramos, instanci&#xE1;ramos o extendi&#xE9;ramos <code>Error</code>(s). Por lo general, queremos que estos se propaguen hasta arriba.</p>
<p>Algunos ejemplos de errores son <code>StackOverflowError</code> y <code>OutOfMemoryError</code>.</p>
<h2 id="span-name4-manejo-de-excepcionesspan-4-manejo-de-excepciones"><span name="4-manejo-de-excepciones"></span> <a href="#4-manejo-de-excepciones">4.</a> Manejo de Excepciones</h2>
<p>En la API de Java, hay muchos lugares donde las cosas pueden salir mal, y algunos de estos lugares est&#xE1;n marcados con excepciones, ya sea en la firma o en el Javadoc:</p>
<pre><code class="language-java">/**
 * @exception FileNotFoundException ...
 */
public Scanner(String fileName) throws FileNotFoundException {
   // ...
}
</code></pre>
<p>Como mencionamos un poco antes, cuando llamamos a estos m&#xE9;todos &quot;arriesgados&quot;, debemos manejar las excepciones verificadas y podemos manejar las no verificadas. Java nos ofrece varias formas de hacer esto:</p>
<h3 id="span-name4-1-throwsspan-41-throws"><span name="4-1-throws"></span> <a href="#4-1-throws">4.1.</a> <em>throws</em></h3>
<p>La forma m&#xE1;s simple de &quot;manejar&quot; una excepci&#xF3;n es relanzarla:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador)
  throws FileNotFoundException {
 
    Scanner contenido = new Scanner(new File(archivoJugador));
    return Integer.parseInt(contenido.nextLine());
}
</code></pre>
<p>Dado que <code>FileNotFoundException</code> es una excepci&#xF3;n verificada, esta es la forma m&#xE1;s sencilla de satisfacer al compilador, <strong>pero significa que cualquiera que llame a nuestro m&#xE9;todo ahora tambi&#xE9;n debe manejarla</strong>.</p>
<p><code>parseInt</code> puede lanzar una <code>NumberFormatException</code>, pero como es una excepci&#xF3;n no verificada, no estamos obligados a manejarla.</p>
<h3 id="span-name4-2-try-catchspan-42-try-catch"><span name="4-2-try-catch"></span> <a href="#4-2-try-catch">4.2.</a> <em>try-catch</em></h3>
<p>Si queremos intentar manejar la excepci&#xF3;n nosotros mismos, podemos usar un bloque <em>try-catch</em>. Podemos manejarlo volviendo a lanzar nuestra excepci&#xF3;n:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        Scanner contenido = new Scanner(new File(archivoJugador));
        return Integer.parseInt(contenido.nextLine());
    } catch (FileNotFoundException noArchivo) {
        throw new IllegalArgumentException(&quot;Archivo no encontrado&quot;);
    }
}
</code></pre>
<p>O realizando pasos de recuperaci&#xF3;n:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        Scanner contenido = new Scanner(new File(archivoJugador));
        return Integer.parseInt(contenido.nextLine());
    } catch ( FileNotFoundException noArchivo ) {
        logger.warn(&quot;Archivo no encontrado, restableciendo puntuaci&#xF3;n.&quot;);
        return 0;
    }
}
</code></pre>
<h3 id="span-name4-3-finallyspan-43-finally"><span name="4-3-finally"></span> <a href="#4-3-finally">4.3.</a> <em>finally</em></h3>
<p>Hay momentos en los que tenemos c&#xF3;digo que debe ejecutarse independientemente de si se produce una excepci&#xF3;n, y aqu&#xED; es donde entra la palabra clave <em>finally</em>.</p>
<p>En nuestros ejemplos hasta ahora, ha habido un error molesto acechando en las sombras, que es que Java, por defecto, no devolver&#xE1; los identificadores de archivos al sistema operativo.</p>
<p>Ciertamente, ya sea que podamos leer el archivo o no, queremos asegurarnos de hacer la limpieza adecuada.</p>
<p>Probemos esto de la manera &quot;perezosa&quot; primero:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador)
  throws FileNotFoundException {
    Scanner contenido = null;
    try {
        contenido = new Scanner(new File(archivoJugador));
        return Integer.parseInt(contenido.nextLine());
    } finally {
        if (contenido != null) {
            contenido.close();
        }
    }
}
</code></pre>
<p>Aqu&#xED;, el bloque <em>finally</em> indica qu&#xE9; c&#xF3;digo queremos que Java ejecute independientemente de lo que suceda al intentar leer el archivo.</p>
<p>Incluso si se lanza una <code>FileNotFoundException</code> hacia arriba en la pila de llamadas, Java llamar&#xE1; al contenido de <em>finally</em> antes de hacerlo.</p>
<p>Tambi&#xE9;n podemos manejar la excepci&#xF3;n y asegurarnos de que nuestros recursos se cierren:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    Scanner contenido;
    try {
        contenido = new Scanner(new File(archivoJugador));
        return Integer.parseInt(contenido.nextLine());
    } catch (FileNotFoundException noArchivo ) {
        logger.warn(&quot;Archivo no encontrado, restableciendo puntuaci&#xF3;n.&quot;);
        return 0; 
    } finally {
        try {
            if (contenido != null) {
                contenido.close();
            }
        } catch (IOException io) {
            logger.error(&quot;No se pudo cerrar el lector!&quot;, io);
        }
    }
}
</code></pre>
<p><strong>Debido a que close tambi&#xE9;n es un m&#xE9;todo &quot;arriesgado&quot;, tambi&#xE9;n necesitamos capturar su excepci&#xF3;n.</strong></p>
<p>Esto puede parecer bastante complicado, pero necesitamos cada pieza para manejar correctamente cada problema potencial que pueda surgir.</p>
<h3 id="span-name4-4-try-with-resourcesspan-44-try-with-resources"><span name="4-4-try-with-resources"></span> <a href="#4-4-try-with-resources">4.4.</a> <em>try-with-resources</em></h3>
<p>Afortunadamente, a partir de Java 7, podemos simplificar la sintaxis anterior cuando trabajamos con elementos que extienden <code>AutoCloseable</code>:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try (Scanner contenido = new Scanner(new File(archivoJugador))) {
      return Integer.parseInt(contenido.nextLine());
    } catch (FileNotFoundException e ) {
      logger.warn(&quot;Archivo no encontrado, restableciendo puntuaci&#xF3;n.&quot;);
      return 0;
    }
}
</code></pre>
<p>Cuando colocamos referencias que son <code>AutoCloseable</code> en la declaraci&#xF3;n <em>try</em>, entonces no necesitamos cerrar el recurso nosotros mismos.</p>
<p>A&#xFA;n podemos usar un bloque <em>finally</em> para realizar cualquier otro tipo de limpieza que deseemos.</p>
<p>En pr&#xF3;ximas publicaciones, veremos un art&#xED;culo dedicado a <em>try-with-resources</em> para explorarlo en mayor profundidad.</p>
<h3 id="span-name4-5-multiples-bloques-catchspan-45-m%C3%BAltiples-bloques-catch"><span name="4-5-multiples-bloques-catch"></span> <a href="#4-5-multiples-bloques-catch">4.5.</a> M&#xFA;ltiples Bloques <em>catch</em></h3>
<p>A veces, el c&#xF3;digo puede generar m&#xE1;s de una excepci&#xF3;n, y podemos tener m&#xE1;s de un bloque <em>catch</em> para manejar cada una individualmente:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try (Scanner contenido = new Scanner(new File(archivoJugador))) {
        return Integer.parseInt(contenido.nextLine());
    } catch (IOException e) {
        logger.warn(&quot;&#xA1;No se pudo cargar el archivo del jugador!&quot;, e);
        return 0;
    } catch (NumberFormatException e) {
        logger.warn(&quot;&#xA1;El archivo del jugador est&#xE1; corrupto!&quot;, e);
        return 0;
    }
}
</code></pre>
<p>Los bloques <em>catch</em> m&#xFA;ltiples nos brindan la oportunidad de manejar cada excepci&#xF3;n de manera diferente, si es necesario.</p>
<p>Tambi&#xE9;n nota aqu&#xED; que no capturamos <code>FileNotFoundException</code>, y eso se debe a que extiende <code>IOException</code>. Dado que estamos capturando <code>IOException</code>, Java considerar&#xE1; que cualquiera de sus subclases tambi&#xE9;n est&#xE1; manejada.</p>
<p>Sin embargo, supongamos que necesitamos tratar <code>FileNotFoundException</code> de manera diferente a la <code>IOException</code> m&#xE1;s general:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try (Scanner contenido = new Scanner(new File(archivoJugador)) ) {
        return Integer.parseInt(contenido.nextLine());
    } catch (FileNotFoundException e) {
        logger.warn(&quot;&#xA1;Archivo del jugador no encontrado!&quot;, e);
        return 0;
    } catch (IOException e) {
        logger.warn(&quot;&#xA1;No se pudo cargar el archivo del jugador!&quot;, e);
        return 0;
    } catch (NumberFormatException e) {
        logger.warn(&quot;&#xA1;El archivo del jugador est&#xE1; corrupto!&quot;, e);
        return 0;
    }
}
</code></pre>
<p>Java nos permite manejar excepciones de subclases por separado, <strong>recuerda colocarlas m&#xE1;s arriba en la lista de catch.</strong></p>
<h3 id="span-name4-6-bloques-catch-de-unionspan-46-bloques-catch-de-uni%C3%B3n"><span name="4-6-bloques-catch-de-union"></span> <a href="#4-6-bloques-catch-de-union">4.6.</a> Bloques <em>catch</em> de Uni&#xF3;n</h3>
<p>Cuando sabemos que la forma en que manejamos los errores ser&#xE1; la misma, Java 7 introdujo la capacidad de capturar m&#xFA;ltiples excepciones en el mismo bloque:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try (Scanner contenido = new Scanner(new File(archivoJugador))) {
        return Integer.parseInt(contenido.nextLine());
    } catch (IOException | NumberFormatException e) {
        logger.warn(&quot;Error al cargar la puntuaci&#xF3;n.&quot;, e);
        return 0;
    }
}
</code></pre>
<h2 id="span-name5-lanzamiento-de-excepcionesspan-5-lanzamiento-de-excepciones"><span name="5-lanzamiento-de-excepciones"></span> <a href="#5-lanzamiento-de-excepciones">5.</a> Lanzamiento de Excepciones</h2>
<p>Si no queremos manejar la excepci&#xF3;n nosotros mismos o queremos generar nuestras propias excepciones para que otros las manejen, entonces necesitamos familiarizarnos con la palabra clave <em>throw</em>.</p>
<p>Supongamos que tenemos la siguiente excepci&#xF3;n verificada que hemos creado nosotros mismos:</p>
<pre><code class="language-java">public class ExcepcionTiempoAgotado extends Exception {
    public ExcepcionTiempoAgotado(String mensaje) {
        super(mensaje);
    }
}
</code></pre>
<p>y tenemos un m&#xE9;todo que podr&#xED;a tomar mucho tiempo en completarse:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) {
    // ... operaci&#xF3;n potencialmente larga
}
</code></pre>
<h3 id="span-name5-1-lanzamiento-de-una-excepcion-verificadaspan-51-lanzamiento-de-una-excepci%C3%B3n-verificada"><span name="5-1-lanzamiento-de-una-excepcion-verificada"></span> <a href="#5-1-lanzamiento-de-una-excepcion-verificada">5.1.</a> Lanzamiento de una Excepci&#xF3;n Verificada</h3>
<p>Al igual que con la devoluci&#xF3;n de un m&#xE9;todo, podemos hacer <em>throw</em> en cualquier punto.</p>
<p>Por supuesto, deber&#xED;amos lanzar cuando intentamos indicar que algo ha salido mal:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) throws ExcepcionTiempoAgotado {
    while ( !demasiadoTiempo ) {
        // ... operaci&#xF3;n potencialmente larga
    }
    throw new ExcepcionTiempoAgotado(&quot;Esta operaci&#xF3;n tard&#xF3; demasiado&quot;);
}
</code></pre>
<p>Dado que <code>ExcepcionTiempoAgotado</code> es verificada, tambi&#xE9;n debemos usar la palabra clave <em>throws</em> en la firma para que los llamadores de nuestro m&#xE9;todo sepan que deben manejarla.</p>
<h3 id="span-name5-2-lanzamiento-de-una-excepcion-no-verificadaspan-52-lanzamiento-de-una-excepci%C3%B3n-no-verificada"><span name="5-2-lanzamiento-de-una-excepcion-no-verificada"></span> <a href="#5-2-lanzamiento-de-una-excepcion-no-verificada">5.2.</a> Lanzamiento de una Excepci&#xF3;n No Verificada</h3>
<p>Si queremos hacer algo como validar la entrada, podemos usar una excepci&#xF3;n no verificada:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) throws ExcepcionTiempoAgotado {
    if (!esNombreDeArchivoValido(archivoJugadores)) {
        throw new IllegalArgumentException(&quot;&#xA1;El nombre de archivo no es v&#xE1;lido!&quot;);
    }
   
    // ...
}
</code></pre>
<p>Dado que <code>IllegalArgumentException</code> no es verificada, no tenemos que marcar el m&#xE9;todo, aunque podemos hacerlo si lo deseamos.</p>
<p>Algunos marcan el m&#xE9;todo de todos modos como una forma de documentaci&#xF3;n.</p>
<h3 id="span-name5-3-envoltura-y-relanzamientospan-53-envoltura-y-relanzamiento"><span name="5-3-envoltura-y-relanzamiento"></span> <a href="#5-3-envoltura-y-relanzamiento">5.3.</a> Envoltura y Relanzamiento</h3>
<p>Tambi&#xE9;n podemos elegir relanzar una excepci&#xF3;n que hemos capturado:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) 
  throws IOException {
    try { 
        // ...
    } catch (IOException io) { 		
        throw io;
    }
}
</code></pre>
<p>O hacer una envoltura y relanzamiento:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) 
  throws ExcepcionCargaJugador {
    try { 
        // ...
    } catch (IOException io) { 		
        throw new ExcepcionCargaJugador(io);
    }
}
</code></pre>
<p>Esto puede ser &#xFA;til para consolidar muchas excepciones diferentes en una.</p>
<h3 id="span-name5-4-relanzamiento-de-throwable-o-exceptionspan-54-relanzamiento-de-throwable-o-exception"><span name="5-4-relanzamiento-de-throwable-o-exception"></span> <a href="#5-4-relanzamiento-de-throwable-o-exception">5.4.</a> Relanzamiento de <em>Throwable</em> o <em>Exception</em></h3>
<p>Ahora, un caso especial.</p>
<p>Si las &#xFA;nicas excepciones posibles que un bloque de c&#xF3;digo podr&#xED;a generar son excepciones no verificadas, entonces podemos capturar y relanzar <code>Throwable</code> o <code>Exception</code> sin agregarlas a la firma de nuestro m&#xE9;todo:</p>
<pre><code class="language-java">public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) {
    try {
        throw new NullPointerException();
    } catch (Throwable t) {
        throw t;
    }
}
</code></pre>
<p>Aunque simple, el c&#xF3;digo anterior no puede lanzar una excepci&#xF3;n verificada y, debido a eso, incluso si estamos relanzando una excepci&#xF3;n verificada, no tenemos que marcar la firma con una cl&#xE1;usula <em>throws</em>.</p>
<p><strong>Esto es &#xFA;til con clases y m&#xE9;todos de proxy.</strong> Puedes encontrar m&#xE1;s informaci&#xF3;n al respecto <a href="https://4comprehension.com/sneakily-throwing-exceptions-in-lambda-expressions-in-java/?ref=javamagician.com">aqu&#xED;</a>.</p>
<h3 id="span-name5-5-herenciaspan-55-herencia"><span name="5-5-herencia"></span> <a href="#5-5-herencia">5.5.</a> Herencia</h3>
<p>Cuando marcamos m&#xE9;todos con una palabra clave <em>throws</em>, afecta c&#xF3;mo las subclases pueden anular nuestro m&#xE9;todo.</p>
<p>En la circunstancia en la que nuestro m&#xE9;todo lanza una excepci&#xF3;n verificada:</p>
<pre><code class="language-java">public class Excepciones {
    public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) 
      throws ExcepcionTiempoAgotado {
        // ...
    }
}
</code></pre>
<p>Una subclase puede tener una firma &quot;menos arriesgada&quot;:</p>
<pre><code class="language-java">public class MenosExcepciones extends Excepciones {	
    @Override
    public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) {
        // anulado
    }
}
</code></pre>
<p>Pero no una firma &quot;m&#xE1;s riesgosa&quot;:</p>
<pre><code class="language-java">public class MasExcepciones extends Excepciones {		
    @Override
    public List&lt;Jugador&gt; cargarTodosLosJugadores(String archivoJugadores) throws MiExcepcionVerificada {
        // anulado
    }
}
</code></pre>
<p>Esto se debe a que los contratos se determinan en tiempo de compilaci&#xF3;n por el tipo de referencia. Si creo una instancia de <code>MasExcepciones</code> y la guardo en <code>Excepciones</code>:</p>
<pre><code class="language-java">Excepciones excepciones = new MasExcepciones();
excepciones.cargarTodosLosJugadores(&quot;archivo&quot;);
</code></pre>
<p>Entonces la JVM solo me indicar&#xE1; que capture <code>ExcepcionTiempoAgotado</code>, lo cual es incorrecto ya que he dicho que <code>MasExcepciones#cargarTodosLosJugadores</code> lanza una excepci&#xF3;n diferente.</p>
<p><strong>En resumen, las subclases pueden lanzar menos excepciones verificadas que su superclase, pero no m&#xE1;s.</strong></p>
<h2 id="span-name6-anti-patronesspan-6-anti-patrones"><span name="6-anti-patrones"></span> <a href="#6-anti-patrones">6.</a> Anti-Patrones</h2>
<h3 id="span-name6-1-tragar-excepcionesspan-61-tragar-excepciones"><span name="6-1-tragar-excepciones"></span> <a href="#6-1-tragar-excepciones">6.1.</a> Tragar Excepciones</h3>
<p>Ahora, hay otra manera en la que podr&#xED;amos haber satisfecho al compilador:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (Exception e) {} // &lt;== captura y traga
    return 0;
}
</code></pre>
<p><strong>Lo anterior se llama tragar (swallowing) una excepci&#xF3;n.</strong> La mayor&#xED;a de las veces, ser&#xED;a un poco malo hacer esto porque no aborda el problema y evita que otro c&#xF3;digo tambi&#xE9;n pueda abordarlo.</p>
<p>Hay momentos en los que hay una excepci&#xF3;n verificada que estamos seguros de que simplemente nunca ocurrir&#xE1;. <strong>En esos casos, al menos deber&#xED;amos agregar un comentario indicando que hemos comido intencionalmente la excepci&#xF3;n</strong>:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (IOException e) {
        // esto nunca suceder&#xE1;
    }
}
</code></pre>
<p>Otra forma de &quot;tragar&quot; una excepci&#xF3;n es imprimir la excepci&#xF3;n en el flujo de errores:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (Exception e) {
        e.printStackTrace();
    }
    return 0;
}
</code></pre>
<p>Hemos mejorado un poco nuestra situaci&#xF3;n al menos escribiendo el error en alg&#xFA;n lugar para un diagn&#xF3;stico posterior.</p>
<p>Ser&#xED;a mejor, sin embargo, usar un registrador:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (IOException e) {
        logger.error(&quot;No se pudo cargar la puntuaci&#xF3;n&quot;, e);
        return 0;
    }
}
</code></pre>
<p>Aunque es muy conveniente manejar las excepciones de esta manera, debemos asegurarnos de no tragar informaci&#xF3;n importante que los llamadores de nuestro c&#xF3;digo podr&#xED;an usar para solucionar el problema.</p>
<p>Finalmente, podemos tragar inadvertidamente una excepci&#xF3;n al no incluirla como una causa cuando estamos lanzando una nueva excepci&#xF3;n:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (IOException e) {
        throw new ExcepcionPuntuacionJugador();
    }
}
</code></pre>
<p>Aqu&#xED;, nos felicitamos por alertar a nuestro llamador sobre un error, pero <strong>no incluimos <code>IOException</code> como la causa</strong>. Debido a esto, hemos perdido informaci&#xF3;n importante que los llamadores u operadores podr&#xED;an usar para diagnosticar el problema.</p>
<p>Ser&#xED;a mejor hacer:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch (IOException e) {
        throw new ExcepcionPuntuacionJugador(e);
    }
}
</code></pre>
<p>Observa la sutil diferencia de incluir <code>IOException</code> como la causa de <code>ExcepcionPuntuacionJugador</code>.</p>
<h3 id="span-name6-2-uso-de-return-en-un-bloque-finallyspan-62-uso-de-return-en-un-bloque-finally"><span name="6-2-uso-de-return-en-un-bloque-finally"></span> <a href="#6-2-uso-de-return-en-un-bloque-finally">6.2.</a> Uso de <em>return</em> en un Bloque <em>finally</em></h3>
<p>Otra manera de tragar excepciones es retornar desde el bloque <em>finally</em>. Esto es perjudicial porque, al retornar abruptamente, la JVM descartar&#xE1; la excepci&#xF3;n, incluso si fue lanzada por nuestro c&#xF3;digo:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    int puntuacion = 0;
    try {
        throw new IOException();
    } finally {
        return puntuacion; // &lt;== la IOException se descarta
    }
}
</code></pre>
<p>De acuerdo con la <a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html?ref=javamagician.com#jls-14.20.2">Especificaci&#xF3;n del Lenguaje Java</a>:</p>
<ul>
<li>
<p>Si la ejecuci&#xF3;n del bloque <em>try</em> se completa abruptamente por cualquier otro motivo X, entonces se ejecuta el bloque <em>finally</em>, y luego hay una elecci&#xF3;n.</p>
</li>
<li>
<p>Si el bloque <em>finally</em> se completa normalmente, entonces la declaraci&#xF3;n <em>try</em> se completa abruptamente por la raz&#xF3;n X.</p>
</li>
<li>
<p>Si el bloque <em>finally</em> se completa abruptamente por la raz&#xF3;n Y, entonces la declaraci&#xF3;n <em>try</em> se completa abruptamente por la raz&#xF3;n Y (y la raz&#xF3;n X se descarta).</p>
</li>
</ul>
<h3 id="span-name6-3-uso-de-throw-en-un-bloque-finallyspan-63-uso-de-throw-en-un-bloque-finally"><span name="6-3-uso-de-throw-en-un-bloque-finally"></span> <a href="#6-3-uso-de-throw-en-un-bloque-finally">6.3.</a> Uso de <em>throw</em> en un Bloque <em>finally</em></h3>
<p>Similar al uso de <em>return</em> en un bloque <em>finally</em>, la excepci&#xF3;n lanzada en un bloque <em>finally</em> tomar&#xE1; precedencia sobre la excepci&#xF3;n que surge en el bloque <em>catch</em>.</p>
<p>Esto &quot;borrar&#xE1;&quot; la excepci&#xF3;n original del bloque <em>try</em>, y perdemos toda esa informaci&#xF3;n valiosa:</p>
<pre><code class="language-java">public int obtenerPuntuacionJugador(String archivoJugador) {
    try {
        // ...
    } catch ( IOException io ) {
        throw new IllegalStateException(io); // &lt;== devorada por el bloque finally
    } finally {
        throw new OtraExcepcion();
    }
}
</code></pre>
<h3 id="span-name6-4-uso-de-throw-como-gotospan-64-uso-de-throw-como-un-goto"><span name="6-4-uso-de-throw-como-goto"></span> <a href="#6-4-uso-de-throw-como-goto">6.4.</a> Uso de <em>throw</em> como un <em>goto</em></h3>
<p>Algunas personas tambi&#xE9;n sucumben a la tentaci&#xF3;n de usar <em>throw</em> como una declaraci&#xF3;n <em>goto</em>:</p>
<pre><code class="language-java">public void hacerAlgo() {
    try {
        // mont&#xF3;n de c&#xF3;digo
        throw new MiExcepcion();
        // segundo mont&#xF3;n de c&#xF3;digo
    } catch (MiExcepcion e) {
        // tercer mont&#xF3;n de c&#xF3;digo
    }		
}
</code></pre>
<p>Esto es extra&#xF1;o porque el c&#xF3;digo est&#xE1; intentando usar excepciones para el control de flujo en lugar de para el manejo de errores.</p>
<h2 id="span-name7-excepciones-y-errores-comunesspan-7-excepciones-y-errores-comunes"><span name="7-excepciones-y-errores-comunes"></span> <a href="#7-excepciones-y-errores-comunes">7.</a> Excepciones y Errores Comunes</h2>
<p>Aqu&#xED; hay algunas excepciones y errores comunes con los que todos nos encontramos de vez en cuando:</p>
<h3 id="span-name7-1-excepciones-verificadasspan-71-excepciones-verificadas"><span name="7-1-excepciones-verificadas"></span> <a href="#7-1-excepciones-verificadas">7.1.</a> Excepciones Verificadas</h3>
<ul>
<li><code>IOException</code>: Esta excepci&#xF3;n suele indicar que algo en la red, el sistema de archivos o la base de datos fall&#xF3;.</li>
</ul>
<h3 id="span-name7-2-excepciones-de-tiempo-de-ejecucionspan-72-excepciones-de-tiempo-de-ejecuci%C3%B3n"><span name="7-2-excepciones-de-tiempo-de-ejecucion"></span> <a href="#7-2-excepciones-de-tiempo-de-ejecucion">7.2.</a> Excepciones de Tiempo de Ejecuci&#xF3;n</h3>
<ul>
<li>
<p><code>ArrayIndexOutOfBoundsException</code>: Esta excepci&#xF3;n significa que intentamos acceder a un &#xED;ndice de array que no existe, como al intentar obtener el &#xED;ndice 5 de un array de longitud 3.</p>
</li>
<li>
<p><code>ClassCastException</code>: Esta excepci&#xF3;n significa que intentamos realizar una conversi&#xF3;n ilegal, como intentar convertir una <code>String</code> en una <code>List</code>. Usualmente podemos evitarlo realizando comprobaciones defensivas con <em>instanceof</em> antes de hacer la conversi&#xF3;n.</p>
</li>
<li>
<p><code>IllegalArgumentException</code>: Esta excepci&#xF3;n es una forma gen&#xE9;rica de decir que uno de los par&#xE1;metros proporcionados al m&#xE9;todo o constructor es inv&#xE1;lido.</p>
</li>
<li>
<p><code>IllegalStateException</code>: Esta excepci&#xF3;n es una forma gen&#xE9;rica de decir que nuestro estado interno, como el estado de nuestro objeto, es inv&#xE1;lido.</p>
</li>
<li>
<p><code>NullPointerException</code>: Esta excepci&#xF3;n significa que intentamos referenciar un objeto <em>null</em>. Usualmente podemos evitarlo realizando comprobaciones defensivas contra <em>null</em> o utilizando <code>Optional</code>.</p>
</li>
<li>
<p><code>NumberFormatException</code>: Esta excepci&#xF3;n significa que intentamos convertir una <code>String</code> en un n&#xFA;mero, pero la <code>String</code> conten&#xED;a caracteres no v&#xE1;lidos, como intentar convertir <code>13f37</code> en un n&#xFA;mero.</p>
</li>
</ul>
<h3 id="span-name7-3-erroresspan-73-errores"><span name="7-3-errores"></span> <a href="#7-3-errores">7.3.</a> Errores</h3>
<ul>
<li>
<p><code>StackOverflowError</code>: Este error significa que la traza de la pila es demasiado grande. Esto a veces puede ocurrir en aplicaciones masivas; sin embargo, generalmente significa que hay una recursi&#xF3;n infinita en nuestro c&#xF3;digo.</p>
</li>
<li>
<p><code>NoClassDefFoundError</code>: Este error significa que una clase no se pudo cargar ya sea porque no est&#xE1; en el classpath o debido a un fallo en la inicializaci&#xF3;n est&#xE1;tica.</p>
</li>
<li>
<p><code>OutOfMemoryError</code>: Este error significa que la JVM no tiene m&#xE1;s memoria disponible para asignar m&#xE1;s objetos. A veces, esto se debe a una fuga de memoria.</p>
</li>
</ul>
<h2 id="span-name8-conclusionspan-8-conclusi%C3%B3n"><span name="8-conclusion"></span> <a href="#8-conclusion">8.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, hemos repasado los conceptos b&#xE1;sicos del manejo de excepciones, as&#xED; como algunos ejemplos de pr&#xE1;cticas buenas y malas.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Guía de Enums en Java]]></title><description><![CDATA[En este tutorial, aprenderemos qué son los enums en Java, como usar enums, los problemas que resuelven y cómo algunos de sus patrones de diseño pueden utilizarse en la práctica.]]></description><link>https://javamagician.com/java-enums/</link><guid isPermaLink="false">6558718d75a8501741a33b07</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Tue, 28 Nov 2023 12:12:25 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/11/java-enums_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introductionspan-1-introducci%C3%B3n"><span name="1-introduction"></span> <a href="#1-introduction">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/11/java-enums_600x750.png" alt="Gu&#xED;a de Enums en Java"><p>En este tutorial, aprenderemos qu&#xE9; son los enumerados (enums) en Java, los problemas que resuelven y c&#xF3;mo algunos de sus patrones de dise&#xF1;o pueden utilizarse en la pr&#xE1;ctica.</p>
<p><strong>Java 5 introdujo por primera vez la palabra clave <em>enum</em></strong>. Esta denota un tipo especial de clase que siempre extiende la clase <code>java.lang.Enum</code>. Para la documentaci&#xF3;n oficial sobre su uso, podemos dirigirnos a la <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Enum.html?ref=javamagician.com">documentaci&#xF3;n</a>.</p>
<p>Las constantes definidas de esta manera hacen que el c&#xF3;digo sea m&#xE1;s legible, permiten la verificaci&#xF3;n en tiempo de compilaci&#xF3;n, documentan la lista de valores aceptados de antemano y evitan comportamientos inesperados debido a valores no v&#xE1;lidos que se pasan.</p>
<p>Aqu&#xED; hay un ejemplo r&#xE1;pido y simple de un enumerado que define el estado de un pedido de pizza; el estado del pedido puede ser <code>ORDENADO</code>, <code>LISTO</code> o <code>ENTREGADO</code>:</p>
<pre><code class="language-java">public enum EstadoPizza {
    ORDENADO,
    LISTO,
    ENTREGADO; 
}
</code></pre>
<p>Adem&#xE1;s, los enumerados vienen con muchos m&#xE9;todos &#xFA;tiles que de otra manera tendr&#xED;amos que escribir si estuvi&#xE9;ramos usando constantes tradicionales <code>public static final</code>.</p>
<h2 id="span-name2-metodos-personalizados-enumeradosspan-2-m%C3%A9todos-personalizados-en-enumerados"><span name="2-metodos-personalizados-enumerados"></span> <a href="#2-metodos-personalizados-enumerados">2.</a> M&#xE9;todos Personalizados en Enumerados</h2>
<p>Ahora que tenemos una comprensi&#xF3;n b&#xE1;sica de qu&#xE9; son los enumerados y c&#xF3;mo podemos usarlos, llevaremos nuestro ejemplo anterior al siguiente nivel definiendo algunos m&#xE9;todos adicionales de la API en el enumerado:</p>
<pre><code class="language-java">public class Pizza {
    private EstadoPizza estado;
    public enum EstadoPizza {
        ORDENADO,
        LISTO,
        ENTREGADO;
    }

    public boolean esEntregable() {
        return obtenerEstado() == EstadoPizza.LISTO;
    }
    
    // M&#xE9;todos que establecen y obtienen la variable de estado.
}
</code></pre>
<h2 id="span-name3-comparacion-tipos-enumeradosspan-3-comparaci%C3%B3n-de-tipos-de-enumerados-usando-el-operador"><span name="3-comparacion-tipos-enumerados"></span> <a href="#3-comparacion-tipos-enumerados">3.</a> Comparaci&#xF3;n de Tipos de Enumerados Usando el Operador &quot;==&quot;</h2>
<p>Dado que los tipos de enumerados aseguran que solo exista una instancia de las constantes en la JVM, podemos usar de manera segura el operador &quot;<mark>&quot; para comparar dos variables, como hicimos en el ejemplo anterior. Adem&#xE1;s, el operador &quot;</mark>&quot; proporciona seguridad en tiempo de compilaci&#xF3;n y tiempo de ejecuci&#xF3;n.</p>
<p>Primero, analizaremos <strong>la seguridad en tiempo de ejecuci&#xF3;n</strong> en el siguiente fragmento, donde usaremos el operador &quot;==&quot; para comparar estados. Cualquiera de los valores puede ser <code>null</code> y no obtendremos un <code>NullPointerException</code>. Por el contrario, si usamos el m&#xE9;todo <code>equals</code>, obtendremos un <code>NullPointerException</code>:</p>
<pre><code class="language-java">if (testPz.obtenerEstado().equals(Pizza.EstadoPizza.ENTREGADO)); 
if (testPz.obtenerEstado() == Pizza.EstadoPizza.ENTREGADO);
</code></pre>
<p>En cuanto a la <strong>seguridad en tiempo de compilaci&#xF3;n</strong>, veamos un ejemplo donde determinaremos que un enumerado de un tipo diferente es igual al compararlo usando el m&#xE9;todo <code>equals</code>. Esto se debe a que los valores del enumerado y el m&#xE9;todo <code>obtenerEstado</code> coinciden coincidentemente; sin embargo, l&#xF3;gicamente la comparaci&#xF3;n deber&#xED;a ser falsa. Evitamos este problema usando el operador &quot;==&quot;.</p>
<p>El compilador se&#xF1;alar&#xE1; la comparaci&#xF3;n como un error de incompatibilidad:</p>
<pre><code class="language-java">if (testPz.obtenerEstado().equals(TestColor.VERDE));
if (testPz.obtenerEstado() == TestColor.VERDE);
</code></pre>
<h2 id="span-name4-uso-tipos-enumerados-switchspan-4-uso-de-tipos-enumerados-en-switch"><span name="4-uso-tipos-enumerados-switch"></span> <a href="#4-uso-tipos-enumerados-switch">4.</a> Uso de Tipos Enumerados en Switch</h2>
<p>Podemos usar tipos enumerados en instrucciones <em>switch</em> tambi&#xE9;n:</p>
<pre><code class="language-java">public int obtenerTiempoEntregaEnDias() {
    switch (estado) {
        case ORDENADO: return 5;
        case LISTO: return 2;
        case ENTREGADO: return 0;
    }
    return 0;
}
</code></pre>
<h2 id="span-name5-campos-metodos-constructores-enumeradosspan-5-campos-m%C3%A9todos-y-constructores-en-enumerados"><span name="5-campos-metodos-constructores-enumerados"></span> <a href="#5-campos-metodos-constructores-enumerados">5.</a> Campos, M&#xE9;todos y Constructores en Enumerados</h2>
<p>Podemos definir constructores, m&#xE9;todos y campos dentro de tipos enumerados, lo que los hace muy poderosos.</p>
<p>A continuaci&#xF3;n, ampliemos el ejemplo anterior implementando la transici&#xF3;n de una etapa de un pedido de pizza a otra. Veremos c&#xF3;mo podemos eliminar las instrucciones <em>if</em> y <em>switch</em> utilizadas anteriormente:</p>
<pre><code class="language-java">public class Pizza {

    private EstadoPizza estado;
    public enum EstadoPizza {
        ORDENADO (5) {
            @Override
            public boolean esOrdenado() {
                return true;
            }
        },
        LISTO (2) {
            @Override
            public boolean esListo() {
                return true;
            }
        },
        ENTREGADO (0) {
            @Override
            public boolean esEntregado() {
                return true;
            }
        };

        private int tiempoEntrega;

        public boolean esOrdenado() { return false; }

        public boolean esListo() { return false; }

        public boolean esEntregado() { return false; }

        public int obtenerTiempoEntrega() {
            return tiempoEntrega;
        }

        EstadoPizza (int tiempoEntrega) {
            this.tiempoEntrega = tiempoEntrega;
        }
    }

    public boolean esEntregable() {
        return this.estado.esListo();
    }

    public void imprimirTiempoEntrega() {
        System.out.println(&quot;El tiempo de entrega es de &quot; + 
          this.obtenerEstado().obtenerTiempoEntrega() + &quot; d&#xED;as&quot;);
    }
    
    // M&#xE9;todos que establecen y obtienen la variable de estado.
}
</code></pre>
<p>El fragmento de prueba a continuaci&#xF3;n demuestra c&#xF3;mo funciona esto:</p>
<pre><code class="language-java">@Test
public void dadoPedidoPizza_cuandoListo_entoncesEntregable() {
    Pizza testPz = new Pizza();
    testPz.setEstado(Pizza.EstadoPizza.LISTO);
    assertTrue(testPz.esEntregable());
}
</code></pre>
<h2 id="span-name6-enumset-enummapspan-6-enumset-y-enummap"><span name="6-enumset-enummap"></span> <a href="#6-enumset-enummap">6.</a> EnumSet y EnumMap</h2>
<h3 id="span-name6-1-enumsetspan-61-enumset"><span name="6-1-enumset"></span> <a href="#6-1-enumset">6.1.</a> EnumSet</h3>
<p>El <code>EnumSet</code> es una implementaci&#xF3;n especializada de <code>Set</code> destinada a usarse con tipos <code>Enum</code>.</p>
<p>En comparaci&#xF3;n con un <code>HashSet</code>, es una representaci&#xF3;n muy eficiente y compacta de un conjunto particular de constantes <code>Enum</code>, gracias a la <em>Representaci&#xF3;n Interna de Vector de Bits</em> que se utiliza. Tambi&#xE9;n proporciona una alternativa segura al tipo basado en <em>int</em> tradicional llamado &quot;<em>bit flags</em>&quot;, lo que nos permite escribir c&#xF3;digo conciso y m&#xE1;s legible.</p>
<p>El <code>EnumSet</code> es una clase abstracta que tiene dos implementaciones, <code>RegularEnumSet</code> y <code>JumboEnumSet</code>, una de las cuales se elige seg&#xFA;n la cantidad de constantes en el enumerado en el momento de la instanciaci&#xF3;n.</p>
<p>Por lo tanto, es una buena idea usar este conjunto siempre que deseemos trabajar con una colecci&#xF3;n de constantes <code>Enum</code> en la mayor&#xED;a de los escenarios (como subconjuntos, adiciones, eliminaciones y operaciones masivas como <code>containsAll</code> y <code>removeAll</code>), y usar <code>Enum.values()</code> si solo queremos iterar sobre todas las constantes posibles.</p>
<p>En el fragmento de c&#xF3;digo a continuaci&#xF3;n, podemos ver c&#xF3;mo usar <code>EnumSet</code> para crear un subconjunto de constantes:</p>
<pre><code class="language-java">public class Pizza {

    private static EnumSet&lt;EstadoPizza&gt; estadosPizzaNoEntregada =
      EnumSet.of(EstadoPizza.ORDENADO, EstadoPizza.LISTO);

    private EstadoPizza estado;

    public enum EstadoPizza {
        // ...
    }

    public boolean esEntregable() {
        return this.estado.esListo();
    }

    public void imprimirTiempoEntrega() {
        System.out.println(&quot;El tiempo de entrega es de &quot; + 
          this.obtenerEstado().obtenerTiempoEntrega() + &quot; d&#xED;as&quot;);
    }

    public static List&lt;Pizza&gt; obtenerTodasLasPizzasNoEntregadas(List&lt;Pizza&gt; input) {
        return input.stream().filter(
          (s) -&gt; estadosPizzaNoEntregada.contains(s.obtenerEstado()))
            .collect(Collectors.toList());
    }

    public void entregar() { 
        if (esEntregable()) { 
            ConfiguracionSistemaEntregaPizza.obtenerInstancia().obtenerEstrategiaEntrega()
              .entregar(this); 
            this.setEstado(EstadoPizza.ENTREGADO); 
        } 
    }
    
    // M&#xE9;todos que establecen y obtienen la variable de estado.
}
</code></pre>
<p>Ejecutar la siguiente prueba demuestra el poder de la implementaci&#xF3;n <code>EnumSet</code> de la interfaz <code>Set</code>:</p>
<pre><code class="language-java">@Test
public void dadoPedidosPizzas_cuandoRecuperandoPizzasNoEntregadas_entoncesRecuperadasCorrectamente() {
    List&lt;Pizza&gt; listaPizzas = new ArrayList&lt;&gt;();
    Pizza pizza1 = new Pizza();
    pizza1.setEstado(Pizza.EstadoPizza.ENTREGADO);

    Pizza pizza2 = new Pizza();
    pizza2.setEstado(Pizza.EstadoPizza.ORDENADO);

    Pizza pizza3 = new Pizza();
    pizza3.setEstado(Pizza.EstadoPizza.ORDENADO);

    Pizza pizza4 = new Pizza();
    pizza4.setEstado(Pizza.EstadoPizza.LISTO);

    listaPizzas.add(pizza1);
    listaPizzas.add(pizza2);
    listaPizzas.add(pizza3);
    listaPizzas.add(pizza4);

    List&lt;Pizza&gt; pizzasNoEntregadas = Pizza.obtenerTodasLasPizzasNoEntregadas(listaPizzas); 
    assertTrue(pizzasNoEntregadas.size() == 3); 
}
</code></pre>
<h3 id="span-name6-2-enummapspan-62-enummap"><span name="6-2-enummap"></span> <a href="#6-2-enummap">6.2.</a> EnumMap</h3>
<p><code>EnumMap</code> es una implementaci&#xF3;n especializada de <code>Map</code> destinada a usarse con constantes Enum como claves. En comparaci&#xF3;n con su contraparte <code>HashMap</code>, es una implementaci&#xF3;n eficiente y compacta que se representa internamente como un array:</p>
<pre><code class="language-java">EnumMap&lt;Pizza.EstadoPizza, Pizza&gt; mapa;
</code></pre>
<p>Veamos un ejemplo de c&#xF3;mo podemos usarlo en la pr&#xE1;ctica:</p>
<pre><code class="language-java">public static EnumMap&lt;EstadoPizza, List&lt;Pizza&gt;&gt; agruparPizzasPorEstado(List&lt;Pizza&gt; listaPizzas) {
    EnumMap&lt;EstadoPizza, List&lt;Pizza&gt;&gt; pizzasPorEstado = new EnumMap&lt;EstadoPizza, List&lt;Pizza&gt;&gt;(EstadoPizza.class);
    
    for (Pizza pizza : listaPizzas) {
        EstadoPizza estado = pizza.obtenerEstado();

        if (pizzasPorEstado.containsKey(estado)) {
            pizzasPorEstado.get(estado).add(pizza);
        } else {
            List&lt;Pizza&gt; nuevaListaPizzas = new ArrayList&lt;Pizza&gt;();
            
            nuevaListaPizzas.add(pizza);
            pizzasPorEstado.put(estado, nuevaListaPizzas);
        }
    }
    
    return pizzasPorEstado;
}
</code></pre>
<p>Ejecutar la siguiente prueba demuestra el poder de la implementaci&#xF3;n <code>EnumMap</code> de la interfaz <code>Map</code>:</p>
<pre><code class="language-java">@Test
public void dadoPedidosPizzas_cuandoLlamamosAgruparPorEstado_entoncesAgrupadosCorrectamente() {
    List&lt;Pizza&gt; listaPizzas = new ArrayList&lt;&gt;();
    Pizza pizza1 = new Pizza();
    pizza1.setEstado(Pizza.EstadoPizza.ENTREGADO);

    Pizza pizza2 = new Pizza();
    pizza2.setEstado(Pizza.EstadoPizza.ORDENADO);

    Pizza pizza3 = new Pizza();
    pizza3.setEstado(Pizza.EstadoPizza.ORDENADO);

    Pizza pizza4 = new Pizza();
    pizza4.setEstado(Pizza.EstadoPizza.LISTO);

    listaPizzas.add(pizza1);
    listaPizzas.add(pizza2);
    listaPizzas.add(pizza3);
    listaPizzas.add(pizza4);

    EnumMap&lt;Pizza.EstadoPizza, List&lt;Pizza&gt;&gt; mapa = Pizza.agruparPizzasPorEstado(listaPizzas);
    assertTrue(mapa.get(Pizza.EstadoPizza.ENTREGADO).size() == 1);
    assertTrue(mapa.get(Pizza.EstadoPizza.ORDENADO).size() == 2);
    assertTrue(mapa.get(Pizza.EstadoPizza.LISTO).size() == 1);
}
</code></pre>
<h2 id="span-name7-implementar-patrones-de-dise%C3%B1o-usando-enumsspan-7-implementar-patrones-de-dise%C3%B1o-usando-enums"><span name="7-implementar-patrones-de-dise&#xF1;o-usando-enums"></span> <a href="#7-implementar-patrones-de-dise%C3%B1o-usando-enums">7.</a> Implementar Patrones de Dise&#xF1;o Usando Enums</h2>
<h3 id="span-name7-1-patron-singletonspan-71-patr%C3%B3n-singleton"><span name="7-1-patron-singleton"></span> <a href="#7-1-patron-singleton">7.1.</a> Patr&#xF3;n Singleton</h3>
<p>Normalmente, implementar una clase usando el patr&#xF3;n Singleton es bastante no trivial. Los enums proporcionan una manera r&#xE1;pida y f&#xE1;cil de implementar singletons.</p>
<p>Adem&#xE1;s, dado que la clase enum implementa la interfaz <code>Serializable</code> bajo el cap&#xF3;, la clase est&#xE1; garantizada como un singleton por la JVM. Esto es a diferencia de la implementaci&#xF3;n convencional, donde tenemos que asegurarnos de que no se creen nuevas instancias durante la deserializaci&#xF3;n.</p>
<p>En el fragmento de c&#xF3;digo a continuaci&#xF3;n, vemos c&#xF3;mo podemos implementar un patr&#xF3;n singleton:</p>
<pre><code class="language-java">public enum ConfiguracionSistemaEntregaPizza {
    INSTANCE;
    ConfiguracionSistemaEntregaPizza() {
        // Configuraci&#xF3;n de inicializaci&#xF3;n que implica
        // la anulaci&#xF3;n de los valores predeterminados como la estrategia de entrega
    }

    private EstrategiaEntregaPizza estrategiaEntrega = EstrategiaEntregaPizza.NORMAL;

    public static ConfiguracionSistemaEntregaPizza obtenerInstancia() {
        return INSTANCE;
    }

    public EstrategiaEntregaPizza obtenerEstrategiaEntrega() {
        return estrategiaEntrega;
    }
}
</code></pre>
<h3 id="span-name7-2-patron-estrategiaspan-72-patr%C3%B3n-de-estrategia"><span name="7-2-patron-estrategia"></span> <a href="#7-2-patron-estrategia">7.2.</a> Patr&#xF3;n de Estrategia</h3>
<p>Convencionalmente, el patr&#xF3;n de estrategia (Strategy) se escribe teniendo una interfaz que es implementada por diferentes clases.</p>
<p>Agregar una nueva estrategia significa agregar una nueva clase de implementaci&#xF3;n. Con enums, podemos lograr esto con menos esfuerzo y agregar una nueva implementaci&#xF3;n significa simplemente definir otra instancia con alguna implementaci&#xF3;n.</p>
<p>El fragmento de c&#xF3;digo a continuaci&#xF3;n muestra c&#xF3;mo implementar el patr&#xF3;n Strategy:</p>
<pre><code class="language-java">public enum EstrategiaEntregaPizza {
    EXPRESS {
        @Override
        public void entregar(Pizza pizza) {
            System.out.println(&quot;La pizza se entregar&#xE1; en modo express&quot;);
        }
    },
    NORMAL {
        @Override
        public void entregar(Pizza pizza) {
            System.out.println(&quot;La pizza se entregar&#xE1; en modo normal&quot;);
        }
    };

    public abstract void entregar(Pizza pizza);
}
</code></pre>
<p>Luego, agregamos el siguiente m&#xE9;todo a la clase Pizza:</p>
<pre><code class="language-java">public void entregar() {
    if (esEntregable()) {
        ConfiguracionSistemaEntregaPizza.obtenerInstancia().getEstrategiaEntrega()
          .entregar(this);
        this.setEstado(Pizza.EstadoPizza.ENTREGADO);
    }
}

@Test
public void dadoPedidoPizza_cuandoEntregado_entoncesPizzaSeEntregaYEstadoCambia() {
    Pizza pizza = new Pizza();
    pizza.setEstado(Pizza.EstadoPizza.LISTO);
    pizza.entregar();
    assertTrue(pizza.obtenerEstado() == Pizza.EstadoPizza.ENTREGADO);
}
</code></pre>
<h2 id="span-name8-java-8-y-enumsspan-8-java-8-y-enums"><span name="8-java-8-y-enums"></span> <a href="#8-java-8-y-enums">8.</a> Java 8 y Enums</h2>
<p>Podemos reescribir la clase <code>Pizza</code> en Java 8 y ver c&#xF3;mo los m&#xE9;todos <code>obtenerTodasLasPizzasNoEntregadas()</code> y <code>agruparPizzasPorEstado()</code> se vuelven tan concisos con el uso de lambdas y las API de <code>Stream</code>:</p>
<pre><code class="language-java">public static List&lt;Pizza&gt; obtenerTodasLasPizzasNoEntregadas(List&lt;Pizza&gt; input) {
    return input.stream().filter(
      (s) -&gt; !estadosPizzaEntregada.contains(s.obtenerEstado()))
        .collect(Collectors.toList());
}

public static EnumMap&lt;EstadoPizza, List&lt;Pizza&gt;&gt; 
  agruparPizzasPorEstado(List&lt;Pizza&gt; listaPizzas) {
    EnumMap&lt;EstadoPizza, List&lt;Pizza&gt;&gt; mapa = listaPizzas.stream().collect(
      Collectors.groupingBy(Pizza::obtenerEstado,
      () -&gt; new EnumMap&lt;&gt;(EstadoPizza.class), Collectors.toList()));
    return mapa;
}
</code></pre>
<h2 id="span-name9-representacion-json-de-enumspan-9-representaci%C3%B3n-json-de-enum"><span name="9-representacion-json-de-enum"></span> <a href="#9-representacion-json-de-enum">9.</a> Representaci&#xF3;n JSON de Enum</h2>
<p>Usando las librerias <a href="https://github.com/FasterXML/jackson?ref=javamagician.com">Jackson</a>, es posible tener una representaci&#xF3;n JSON de los tipos enum como si fueran POJOs (Plain Old Java Object, es decir, los viejos y confiables objetos planos de Java). En el fragmento de c&#xF3;digo a continuaci&#xF3;n, veremos c&#xF3;mo podemos usar las anotaciones de Jackson para lo mismo:</p>
<pre><code class="language-java">@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum EstadoPizza {
    ORDENADO (5) {
        @Override
        public boolean esOrdenado() {
            return true;
        }
    },
    LISTO (2) {
        @Override
        public boolean esListo() {
            return true;
        }
    },
    ENTREGADO (0) {
        @Override
        public boolean esEntregado() {
            return true;
        }
    };

    private int tiempoEntrega;

    public boolean esOrdenado() {return false;}

    public boolean esListo() {return false;}

    public boolean esEntregado(){return false;}

    @JsonProperty(&quot;tiempoEntrega&quot;)
    public int obtenerTiempoEntrega() {
        return tiempoEntrega;
    }

    private EstadoPizza (int tiempoEntrega) {
        this.tiempoEntrega = tiempoEntrega;
    }
}

Podemos usar la clase Pizza y EstadoPizza de la siguiente manera:

```java
Pizza pizza = new Pizza();
pizza.setEstado(Pizza.EstadoPizza.LISTO);
System.out.println(Pizza.getJsonString(pizza));
</code></pre>
<p>Esto generar&#xE1; la siguiente representaci&#xF3;n JSON del estado de las pizzas:</p>
<pre><code class="language-json">{
  &quot;estado&quot; : {
    &quot;tiempoEntrega&quot; : 2,
    &quot;listo&quot; : true,
    &quot;ordenado&quot; : false,
    &quot;entregado&quot; : false
  },
  &quot;entregable&quot; : true
}
</code></pre>
<p>Para obtener m&#xE1;s informaci&#xF3;n sobre Jackson, puedes consultar su <a href="https://github.com/FasterXML/jackson-docs?ref=javamagician.com">documentaci&#xF3;n</a>.</p>
<h2 id="span-name10-conclusionspan-10-conclusi%C3%B3n"><span name="10-conclusion"></span> <a href="#10-conclusion">10.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, exploramos el enum de Java, desde los conceptos b&#xE1;sicos del lenguaje hasta casos de uso del mundo real m&#xE1;s avanzados e interesantes.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Sobrecarga y Sobrescritura de Métodos en Java]]></title><description><![CDATA[La sobrecarga y sobrescritura de métodos son conceptos clave del lenguaje de programación Java.

En este artículo, aprenderemos los conceptos básicos de veremos en qué situaciones pueden ser útiles, que son y como usar sobrecarga y sobrescritura de métodos.]]></description><link>https://javamagician.com/java-sobrecarga-sobrescritura-metodos/</link><guid isPermaLink="false">653f80a26be40604eb51540d</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Mon, 30 Oct 2023 11:03:39 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-sobrecarga-sobrescritura-metodos_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-sobrecarga-sobrescritura-metodos_600x750.png" alt="Sobrecarga y Sobrescritura de M&#xE9;todos en Java"><p>La sobrecarga y sobrescritura de m&#xE9;todos son conceptos clave del lenguaje de programaci&#xF3;n Java, y como tales, merecen un an&#xE1;lisis en profundidad.</p>
<p>En este art&#xED;culo, aprenderemos los conceptos b&#xE1;sicos de estos conceptos y veremos en qu&#xE9; situaciones pueden ser &#xFA;tiles.</p>
<h2 id="span-name2-sobrecarga-de-metodosspan-2-sobrecarga-de-m%C3%A9todos"><span name="2-sobrecarga-de-metodos"></span> <a href="#2-sobrecarga-de-metodos">2.</a> Sobrecarga de M&#xE9;todos</h2>
<p><strong>La sobrecarga de m&#xE9;todos (overload) es un mecanismo poderoso que nos permite definir API de clases cohesivas</strong>. Para comprender mejor por qu&#xE9; la sobrecarga de m&#xE9;todos es una caracter&#xED;stica tan valiosa, veamos un ejemplo simple.</p>
<p>Supongamos que hemos escrito una clase de utilidad ingenua que implementa diferentes m&#xE9;todos para multiplicar dos n&#xFA;meros, tres n&#xFA;meros, y as&#xED; sucesivamente.</p>
<p>Si hemos dado a los m&#xE9;todos nombres confusos o ambiguos, como <code>multiplicar2()</code>, <code>multiplicar3()</code>, <code>multiplicar4()</code>, entonces esa ser&#xED;a una API de clase mal dise&#xF1;ada. Aqu&#xED; es donde entra en juego la sobrecarga de m&#xE9;todos.</p>
<p><strong>En pocas palabras, podemos implementar la sobrecarga de m&#xE9;todos de dos maneras diferentes</strong>:</p>
<ul>
<li>implementando dos o m&#xE1;s <strong>m&#xE9;todos que tienen el mismo nombre pero toman un n&#xFA;mero diferente de argumentos</strong></li>
<li>implementando dos o m&#xE1;s <strong>m&#xE9;todos que tienen el mismo nombre pero toman argumentos de diferentes tipos</strong></li>
</ul>
<h3 id="span-name2-1-numero-de-argumentos-diferentesspan-21-n%C3%BAmero-de-argumentos-diferentes"><span name="2-1-numero-de-argumentos-diferentes"></span> <a href="#2-1-numero-de-argumentos-diferentes">2.1.</a> N&#xFA;mero de Argumentos Diferentes</h3>
<p>La clase <code>Multiplicador</code> muestra, en pocas palabras, c&#xF3;mo sobrecargar el m&#xE9;todo <code>multiplicar()</code> simplemente definiendo dos implementaciones que toman un n&#xFA;mero diferente de argumentos:</p>
<pre><code class="language-java">public class Multiplicador {
    
    public int multiplicar(int a, int b) {
        return a * b;
    }
    
    public int multiplicar(int a, int b, int c) {
        return a * b * c;
    }
}
</code></pre>
<h3 id="span-name2-2-argumentos-de-tipos-diferentesspan-22-argumentos-de-tipos-diferentes"><span name="2-2-argumentos-de-tipos-diferentes"></span> <a href="#2-2-argumentos-de-tipos-diferentes">2.2.</a> Argumentos de Tipos Diferentes</h3>
<p>De manera similar, podemos sobrecargar el m&#xE9;todo <code>multiplicar()</code> haciendo que acepte argumentos de diferentes tipos:</p>
<pre><code class="language-java">public class Multiplicador {
    
    public int multiplicar(int a, int b) {
        return a * b;
    }
    
    public double multiplicar(double a, double b) {
        return a * b;
    }
}
</code></pre>
<p>Adem&#xE1;s, es leg&#xED;timo definir la clase <code>Multiplicador</code> con ambos tipos de sobrecarga de m&#xE9;todos:</p>
<pre><code class="language-java">public class Multiplicador {
    
    public int multiplicar(int a, int b) {
        return a * b;
    }
    
    public int multiplicar(int a, int b, int c) {
        return a * b * c;
    }
    
    public double multiplicar(double a, double b) {
        return a * b;
    }
</code></pre>
<p>Es importante destacar, sin embargo, que <strong>no es posible tener dos implementaciones de m&#xE9;todos que difieran solo en sus tipos de retorno</strong>.</p>
<p>Para entender por qu&#xE9;, consideremos el siguiente ejemplo:</p>
<pre><code class="language-java">public int multiplicar(int a, int b) { 
    return a * b; 
}
 
public double multiplicar(int a, int b) { 
    return a * b; 
}
</code></pre>
<p>En este caso, <strong>el c&#xF3;digo simplemente no se compilar&#xED;a debido a la ambig&#xFC;edad en la llamada al m&#xE9;todo</strong>: el compilador no sabr&#xED;a qu&#xE9; implementaci&#xF3;n de <code>multiplicar()</code> llamar.</p>
<h3 id="span-name2-3-promocion-de-tiposspan-23-promoci%C3%B3n-de-tipos"><span name="2-3-promocion-de-tipos"></span> <a href="#2-3-promocion-de-tipos">2.3.</a> Promoci&#xF3;n de Tipos</h3>
<p>Una caracter&#xED;stica interesante proporcionada por la sobrecarga de m&#xE9;todos es la llamada promoci&#xF3;n de tipos.</p>
<p>En t&#xE9;rminos simples, un tipo dado se promociona impl&#xED;citamente a otro cuando no hay coincidencia entre los tipos de los argumentos pasados al m&#xE9;todo sobrecargado y una implementaci&#xF3;n espec&#xED;fica del m&#xE9;todo.</p>
<p>Para comprender con m&#xE1;s claridad c&#xF3;mo funciona la promoci&#xF3;n de tipos, consideremos las siguientes implementaciones del m&#xE9;todo <code>multiplicar()</code>:</p>
<pre><code class="language-java">public double multiplicar(int a, long b) {
    return a * b;
}

public int multiplicar(int a, int b, int c) {
    return a * b * c;
</code></pre>
<p>Ahora, llamar al m&#xE9;todo con dos argumentos de tipo <code>int</code> resultar&#xE1; en que el segundo argumento se promocione a <code>long</code>, ya que en este caso no hay una implementaci&#xF3;n coincidente del m&#xE9;todo con dos argumentos de tipo <code>int</code>.</p>
<p>Veamos una prueba unitaria r&#xE1;pida para demostrar la promoci&#xF3;n de tipos:</p>
<pre><code class="language-java">@Test
public void cuandoLlamamosMultiplicarSinCoincidir_entoncesPromocionamosTipo() {
    assertThat(multiplicador.multiplicar(10, 10)).isEqualTo(100.0);
}
</code></pre>
<p>Por otro lado, si llamamos al m&#xE9;todo con una implementaci&#xF3;n coincidente, la promoci&#xF3;n de tipos simplemente no tiene lugar:</p>
<pre><code class="language-java">@Test
public void cuandoLlamamosMultiplicarCoincidiendo_entoncesNoPromocionamosTipo() {
    assertThat(multiplicador.multiplicar(10, 10, 10)).isEqualTo(1000);
}
</code></pre>
<p>Aqu&#xED; tienes un resumen de las reglas de promoci&#xF3;n de tipos que se aplican a la sobrecarga de m&#xE9;todos:</p>
<ul>
<li><code>byte</code> se puede promocionar a <code>short</code>, <code>int</code>, <code>long</code>, <code>float</code> o <code>double</code></li>
<li><code>short</code> se puede promocionar a <code>int</code>, <code>long</code>, <code>float</code> o <code>double</code></li>
<li><code>char</code> se puede promocionar a <code>int</code>, <code>long</code>, <code>float</code> o <code>double</code></li>
<li><code>int</code> se puede promocionar a <code>long</code>, <code>float</code> o <code>double</code></li>
<li><code>long</code> se puede promocionar a <code>float</code> o <code>double</code></li>
<li><code>float</code> se puede promocionar a <code>double</code></li>
</ul>
<h3 id="span-name2-4-vinculacion-estaticaspan-24-vinculaci%C3%B3n-est%C3%A1tica"><span name="2-4-vinculacion-estatica"></span> <a href="#2-4-vinculacion-estatica">2.4.</a> Vinculaci&#xF3;n Est&#xE1;tica</h3>
<p>La capacidad de asociar una llamada de m&#xE9;todo espec&#xED;fica al cuerpo del m&#xE9;todo se conoce como vinculaci&#xF3;n.</p>
<p>En el caso de la sobrecarga de m&#xE9;todos, la vinculaci&#xF3;n se realiza est&#xE1;ticamente en tiempo de compilaci&#xF3;n, por lo que se llama vinculaci&#xF3;n est&#xE1;tica.</p>
<p>El compilador puede establecer eficazmente la vinculaci&#xF3;n en tiempo de compilaci&#xF3;n simplemente comprobando las firmas de los m&#xE9;todos.</p>
<h2 id="span-name3-sobrescritura-de-metodosspan-3-sobrescritura-de-m%C3%A9todos"><span name="3-sobrescritura-de-metodos"></span> <a href="#3-sobrescritura-de-metodos">3.</a> Sobrescritura de M&#xE9;todos</h2>
<p><strong>La sobrescritura de m&#xE9;todos (override) nos permite proporcionar implementaciones detalladas en las subclases para los m&#xE9;todos definidos en una clase base.</strong></p>
<p>Si bien la sobrescritura de m&#xE9;todos es una caracter&#xED;stica poderosa, considerando que es una consecuencia l&#xF3;gica del uso de la <a href="https://javamagician.com/java-herencia/">herencia</a>, uno de los pilares m&#xE1;s importantes de la <a href="https://javamagician.com/tag/oop/">POO</a>, <strong>cu&#xE1;ndo y d&#xF3;nde utilizarla debe analizarse cuidadosamente, caso por caso</strong>.</p>
<p>Veamos ahora c&#xF3;mo utilizar la sobrescritura de m&#xE9;todos creando una relaci&#xF3;n simple de herencia (&quot;es-un&quot;).</p>
<p>Aqu&#xED; est&#xE1; la clase base:</p>
<pre><code class="language-java">public class Vehiculo {
    
    public String acelerar(long mph) {
        return &quot;El veh&#xED;culo acelera a: &quot; + mph + &quot; MPH.&quot;;
    }
    
    public String detener() {
        return &quot;El veh&#xED;culo se ha detenido.&quot;;
    }
    
    public String correr() {
        return &quot;El veh&#xED;culo est&#xE1; en movimiento.&quot;;
    }
}
</code></pre>
<p>Y aqu&#xED; hay una subclase creada de manera forzada:</p>
<pre><code class="language-java">public class Coche extends Vehiculo {

    @Override
    public String acelerar(long mph) {
        return &quot;El coche acelera a: &quot; + mph + &quot; MPH.&quot;;
    }
}
</code></pre>
<p>En la jerarqu&#xED;a anterior, simplemente hemos sobrescrito el m&#xE9;todo <code>acelerar()</code> para proporcionar una implementaci&#xF3;n m&#xE1;s refinada para el subtipo <code>Coche</code>.</p>
<p>Aqu&#xED;, queda claro que <strong>si una aplicaci&#xF3;n utiliza instancias de la clase <code>Veh&#xED;culo</code>, tambi&#xE9;n puede trabajar con instancias de <code>Coche</code></strong>, ya que ambas implementaciones del m&#xE9;todo <code>acelerar()</code> tienen la misma firma y el mismo tipo de retorno.</p>
<p>Escribamos algunas pruebas unitarias para comprobar las clases <code>Veh&#xED;culo</code> y <code>Coche</code>:</p>
<pre><code class="language-java">@Test
public void cuandoLlamamosAcelerar_entoncesComprobamos() {
    assertThat(vehiculo.acelerar(100))
      .isEqualTo(&quot;El veh&#xED;culo acelera a: 100 MPH.&quot;);
}
    
@Test
public void cuandoLlamamosCorrer_entoncesComprobamos() {
    assertThat(vehiculo.correr())
      .isEqualTo(&quot;El veh&#xED;culo est&#xE1; en movimiento.&quot;);
}
    
@Test
public void cuandoLlamamosDetener_entoncesComprobamos() {
    assertThat(vehiculo.detener())
      .isEqualTo(&quot;El veh&#xED;culo se ha detenido.&quot;);
}

@Test
public void cuandoLlamamosAcelerar_entoncesComprobamos() {
    assertThat(coche.acelerar(80))
      .isEqualTo(&quot;El coche acelera a: 80 MPH.&quot;);
}
    
@Test
public void cuandoLlamamosCorrer_entoncesComprobamos() {
    assertThat(coche.correr())
      .isEqualTo(&quot;El veh&#xED;culo est&#xE1; en movimiento.&quot;);
}
    
@Test
public void cuandoLlamamosDetener_entoncesComprobamos() {
    assertThat(coche.detener())
      .isEqualTo(&quot;El veh&#xED;culo se ha detenido.&quot;);
}
</code></pre>
<p>Ahora, veamos algunas pruebas unitarias que muestran c&#xF3;mo los m&#xE9;todos <code>correr()</code> y <code>detener()</code>, que no se han sobrescrito, devuelven valores iguales tanto para <code>Coche</code> como para <code>Veh&#xED;culo</code>:</p>
<pre><code class="language-java">@Test
public void dadasInstanciasVehiculoCoche_cuandoLlamamosCorrer_entoncesSonIguales() {
    assertThat(vehiculo.correr()).isEqualTo(coche.correr());
}
 
@Test
public void dadasInstanciasVehiculoCoche_cuandoLlamamosDetener_entoncesSonIguales() {
   assertThat(vehiculo.detener()).isEqualTo(coche.detener());
}
</code></pre>
<p>En nuestro caso, tenemos acceso al c&#xF3;digo fuente de ambas clases, por lo que podemos ver claramente que llamar al m&#xE9;todo <code>acelerar()</code> en una instancia base de <code>Veh&#xED;culo</code> y llamar a <code>acelerar()</code> en una instancia de <code>Coche</code> devolver&#xE1; valores diferentes para el mismo argumento.</p>
<p>Por lo tanto, la siguiente prueba demuestra que el m&#xE9;todo sobrescrito se invoca para una instancia de <code>Coche</code>:</p>
<pre><code class="language-java">@Test
public void cuandoLlamamosAcelerarConElMismoArgumento_entoncesNoSonIguales() {
    assertThat(vehiculo.acelerar(100))
      .isNotEqualTo(coche.acelerar(100));
}
</code></pre>
<h3 id="span-name3-1-substitucion-de-tiposspan-31-substituci%C3%B3n-de-tipos"><span name="3-1-substitucion-de-tipos"></span> <a href="#3-1-substitucion-de-tipos">3.1.</a> Substituci&#xF3;n de Tipos</h3>
<p>Un principio fundamental en la POO es el de la substituci&#xF3;n de tipos, que est&#xE1; estrechamente relacionado con el <a href="https://es.wikipedia.org/wiki/Principio_de_sustituci%C3%B3n_de_Liskov?ref=javamagician.com">Principio de Substituci&#xF3;n de Liskov (LSP)</a>.</p>
<p>En pocas palabras, el LSP establece que <strong>si una aplicaci&#xF3;n trabaja con un tipo base dado, tambi&#xE9;n deber&#xED;a funcionar con cualquiera de sus subtipos</strong>. De esta manera, se conserva adecuadamente la substituci&#xF3;n de tipos.</p>
<p><strong>El mayor problema con la sobrescritura de m&#xE9;todos es que algunas implementaciones espec&#xED;ficas de m&#xE9;todos en las clases derivadas podr&#xED;an no adherirse completamente al LSP y, por lo tanto, no conservar la substituci&#xF3;n de tipos.</strong></p>
<p>Por supuesto, es v&#xE1;lido hacer que un m&#xE9;todo sobrescrito acepte argumentos de diferentes tipos y devuelva un tipo diferente, pero con plena adherencia a estas reglas:</p>
<ul>
<li>Si un m&#xE9;todo en la clase base toma argumento(s) de un tipo dado, el m&#xE9;todo sobrescrito deber&#xED;a tomar el mismo tipo o un supertipo (tambi&#xE9;n conocido como argumentos contravariantes).</li>
<li>Si un m&#xE9;todo en la clase base devuelve <em>void</em>, el m&#xE9;todo sobrescrito deber&#xED;a devolver <em>void</em>.</li>
<li>Si un m&#xE9;todo en la clase base devuelve un primitivo, el m&#xE9;todo sobrescrito deber&#xED;a devolver el mismo primitivo.</li>
<li>Si un m&#xE9;todo en la clase base devuelve un cierto tipo, el m&#xE9;todo sobrescrito deber&#xED;a devolver el mismo tipo o un subtipo (tambi&#xE9;n conocido como tipo de retorno covariante).</li>
<li>Si un m&#xE9;todo en la clase base lanza una excepci&#xF3;n, el m&#xE9;todo sobrescrito debe lanzar la misma excepci&#xF3;n o un subtipo de la excepci&#xF3;n de la clase base.</li>
</ul>
<h3 id="span-name3-2-vinculacion-dinamicaspan-32-vinculaci%C3%B3n-din%C3%A1mica"><span name="3-2-vinculacion-dinamica"></span> <a href="#3-2-vinculacion-dinamica">3.2.</a> Vinculaci&#xF3;n Din&#xE1;mica</h3>
<p>Dado que la sobrescritura de m&#xE9;todos solo se puede implementar con la herencia, donde hay una jerarqu&#xED;a de un tipo base y subtipos, el compilador no puede determinar en tiempo de compilaci&#xF3;n qu&#xE9; m&#xE9;todo llamar, ya que tanto la clase base como las subclases definen los mismos m&#xE9;todos.</p>
<p>Como consecuencia, el compilador necesita verificar el tipo de objeto para saber qu&#xE9; m&#xE9;todo debe ser invocado.</p>
<p>Dado que esta verificaci&#xF3;n ocurre en tiempo de ejecuci&#xF3;n, la sobrescritura de m&#xE9;todos es un ejemplo t&#xED;pico de vinculaci&#xF3;n din&#xE1;mica.</p>
<h2 id="span-name4-conclusionspan-4-conclusi%C3%B3n"><span name="4-conclusion"></span> <a href="#4-conclusion">4.</a> Conclusi&#xF3;n</h2>
<p>En este tutorial, aprendimos c&#xF3;mo implementar la sobrecarga de m&#xE9;todos y la sobrescritura de m&#xE9;todos, y exploramos algunas situaciones t&#xED;picas en las que son &#xFA;tiles.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[La Palabra Clave super en Java]]></title><description><![CDATA[En este breve tutorial, como utilizar la palabra clave super en Java.
Exploremos las aplicaciones de esta palabra clave fundamental en el lenguaje, ya que saber como usar super en Java en esencial.]]></description><link>https://javamagician.com/java-palabra-clave-super/</link><guid isPermaLink="false">653976346be40604eb5153bc</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Wed, 25 Oct 2023 20:44:12 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-palabra-clave-super_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-palabra-clave-super_600x750.png" alt="La Palabra Clave super en Java"><p>En este breve tutorial, <strong>echaremos un vistazo a la palabra clave <em>super</em> en Java.</strong></p>
<p><strong>En pocas palabras, podemos usar la palabra clave <em>super</em> para acceder a la clase padre.</strong></p>
<p>Exploremos las aplicaciones de esta palabra clave fundamental en el lenguaje.</p>
<h2 id="span-name2-la-palabra-clave-super-con-constructoresspan-2-la-palabra-clave-super-con-constructores"><span name="2-la-palabra-clave-super-con-constructores"></span> <a href="#2-la-palabra-clave-super-con-constructores">2.</a> La Palabra Clave <em>super</em> con Constructores</h2>
<p><strong>Podemos usar <code>super()</code> para llamar al constructor por defecto de la clase padre.</strong> Debe ser la primera declaraci&#xF3;n en un constructor.</p>
<p>En nuestro ejemplo, usamos <code>super(mensaje)</code> con el argumento de tipo String:</p>
<pre><code class="language-java">public class SubClase extends SuperClase {

    public SubClase(String mensaje) {
        super(mensaje);
    }
}
</code></pre>
<p>Creemos una instancia de la clase hija y veamos lo que sucede detr&#xE1;s:</p>
<pre><code class="language-java">SubClase hijo = new SubClase(&quot;mensaje desde la clase hija&quot;);
</code></pre>
<p>La palabra clave <em>new</em> invoca el constructor de <code>SubClase</code>, que a su vez llama primero al constructor de la clase padre y le pasa el argumento de tipo <em>String</em>.</p>
<h2 id="span-name3-acceso-a-variables-de-la-clase-padrespan-3-acceso-a-variables-de-la-clase-padre"><span name="3-acceso-a-variables-de-la-clase-padre"></span> <a href="#3-acceso-a-variables-de-la-clase-padre">3.</a> Acceso a Variables de la Clase Padre</h2>
<p>Creemos una clase padre con la variable de instancia <code>mensaje</code>:</p>
<pre><code class="language-java">public class SuperClase {
    String mensaje = &quot;clase super&quot;;

    // constructor por defecto

    public SuperClase(String mensaje) {
        this.mensaje = mensaje;
    }
}
</code></pre>
<p>Ahora, creemos una clase hija con una variable del mismo nombre:</p>
<pre><code class="language-java">public class SubClase extends SuperClase {

    String mensaje = &quot;clase hija&quot;;

    public void obtenerMensajePadre() {
        System.out.println(super.mensaje);
    }
}
</code></pre>
<p>Podemos acceder a la variable de la clase padre desde la clase hija utilizando la palabra clave <em>super</em>.</p>
<h2 id="span-name4-el-super-palabra-clave-con-la-sobrescritura-de-metodosspan-4-la-palabra-clave-super-con-la-sobrescritura-de-m%C3%A9todos"><span name="4-el-super-palabra-clave-con-la-sobrescritura-de-metodos"></span> <a href="#4-el-super-palabra-clave-con-la-sobrescritura-de-metodos">4.</a> La Palabra Clave &apos;super&apos; con la Sobrescritura de M&#xE9;todos</h2>
<p>En la siguiente lecci&#xF3;n, hablaremos sobre la sobrescritura de m&#xE9;todos y entraremos en m&#xE1;s detalle. Por el momento, veamos este ejemplo:</p>
<p>Agreguemos un m&#xE9;todo de instancia a nuestra clase padre:</p>
<pre><code class="language-java">public class SuperClase {

    String mensaje = &quot;clase super&quot;;

    public void imprimirMensaje() {
        System.out.println(mensaje);
    }
}
</code></pre>
<p>Y sobrescribamos el m&#xE9;todo <code>imprimirMensaje()</code> en nuestra clase hija:</p>
<pre><code class="language-java">public class SubClase extends SuperClase {

    String mensaje = &quot;clase hija&quot;;

    public SubClase() {
        super.imprimirMensaje();
        imprimirMensaje();
    }

    public void imprimirMensaje() {
        System.out.println(mensaje);
    }
}
</code></pre>
<p><strong>Podemos usar <em>super</em> para acceder al m&#xE9;todo sobrescrito desde la clase hija.</strong> <code>super.imprimirMensaje()</code> en el constructor llama al m&#xE9;todo de la clase padre de <code>SuperClase</code>.</p>
<h2 id="span-name5-conclusionspan-5-conclusi%C3%B3n"><span name="5-conclusion"></span> <a href="#5-conclusion">5.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, hemos explorado la palabra clave <em>super</em> en m&#xE1;s profundidad.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[La Palabra Clave this en Java]]></title><description><![CDATA[En este tutorial, echaremos un vistazo a la palabra clave this en Java. En Java, la palabra clave this es una referencia al objeto actual cuyo método se está llamando. Exploraremos cómo y cuándo podemos usar this en Java.]]></description><link>https://javamagician.com/java-palabra-clave-this/</link><guid isPermaLink="false">6537ac5d6be40604eb51532b</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Tue, 24 Oct 2023 14:39:15 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-palabra-clave-this_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-palabra-clave-this_600x750.png" alt="La Palabra Clave this en Java"><p>En este tutorial, <strong>echaremos un vistazo a la palabra clave <em>this</em> en Java</strong>.</p>
<p>En Java, <strong>la palabra clave <em>this</em> es una referencia al objeto actual cuyo m&#xE9;todo se est&#xE1; llamando.</strong></p>
<p>Exploraremos c&#xF3;mo y cu&#xE1;ndo podemos usar esta palabra clave.</p>
<h2 id="span-name2-desambiguacion-de-sombreado-de-camposspan-2-desambiguaci%C3%B3n-de-sombreado-de-campos"><span name="2-desambiguacion-de-sombreado-de-campos"></span> <a href="#2-desambiguacion-de-sombreado-de-campos">2.</a> Desambiguaci&#xF3;n de Sombreado de Campos</h2>
<p><strong>La palabra clave <em>this</em> es &#xFA;til para desambiguar y diferenciar las variables de instancia de los par&#xE1;metros locales</strong>. La raz&#xF3;n m&#xE1;s com&#xFA;n es cuando tenemos par&#xE1;metros de constructor con el mismo nombre que los campos de instancia:</p>
<pre><code class="language-java">public class PruebaPalabraClave {

    private String nombre;
    private int edad;
    
    public PruebaPalabraClave(String nombre, int edad) {
        this.nombre = nombre;
        this.edad = edad;
    }
}
</code></pre>
<p>Como podemos ver aqu&#xED;, estamos usando <em>this</em> con los campos <code>nombre</code> y <code>edad</code> de instancia para distinguirlos de los par&#xE1;metros.</p>
<p>Otro uso es utilizar <em>this</em> con el ocultamiento o sombreado de par&#xE1;metros en el &#xE1;mbito local.</p>
<h2 id="span-name3-referencia-a-constructores-de-la-misma-clasespan-3-referencia-a-constructores-de-la-misma-clase"><span name="3-referencia-a-constructores-de-la-misma-clase"></span> <a href="#3-referencia-a-constructores-de-la-misma-clase">3.</a> Referencia a Constructores de la Misma Clase</h2>
<p><strong>Desde un constructor, podemos usar <code>this()</code> para llamar a un constructor diferente de la misma clase</strong>. Aqu&#xED;, usamos <code>this()</code> para la concatenaci&#xF3;n de constructores y reducir el uso de c&#xF3;digo.</p>
<p>El caso de uso m&#xE1;s com&#xFA;n es llamar a un constructor por defecto desde un constructor parametrizado:</p>
<pre><code class="language-java">public PruebaPalabraClave(String nombre, int edad) {
    this();
    
    // el resto del c&#xF3;digo
}
</code></pre>
<p>O podemos llamar al constructor parametrizado desde el constructor sin argumentos y pasar algunos argumentos:</p>
<pre><code class="language-java">public PruebaPalabraClave() {
    this(&quot;Manu&quot;, 31);
}
</code></pre>
<p>Ten en cuenta que <code>this()</code> debe ser la primera declaraci&#xF3;n en el constructor, de lo contrario, se producir&#xE1; un error de compilaci&#xF3;n.</p>
<h2 id="span-name4-pasar-this-como-parametrospan-4-pasar-this-como-par%C3%A1metro"><span name="4-pasar-this-como-parametro"></span> <a href="#4-pasar-this-como-parametro">4.</a> Pasar <em>this</em> como Par&#xE1;metro</h2>
<p>Aqu&#xED; tenemos el m&#xE9;todo <code>imprimirInstancia()</code>, donde se define el argumento <code>thisPalabraClave</code>:</p>
<pre><code class="language-java">public PruebaPalabraClave() {
    imprimirInstancia(this);
}

public void imprimirInstancia(PruebaPalabraClave thisPalabraClave) {
    System.out.println(thisPalabraClave);
}
</code></pre>
<p>Dentro del constructor, invocamos el m&#xE9;todo <code>imprimirInstancia()</code>. Con <code>this</code>, pasamos una referencia a la instancia actual.</p>
<h2 id="span-name5-devolver-thisspan-5-devolver-this"><span name="5-devolver-this"></span> <a href="#5-devolver-this">5.</a> Devolver <em>this</em></h2>
<p><strong>Tambi&#xE9;n podemos usar la palabra clave <em>this</em> para devolver la instancia de la clase actual</strong> desde el m&#xE9;todo.</p>
<p>Aqu&#xED; tienes un ejemplo pr&#xE1;ctico completo de c&#xF3;mo se implementa en el patr&#xF3;n de dise&#xF1;o constructor (builder). Este ejemplo tiene solo una clase, <code>CuentaBancaria</code>, que contiene un constructor como una clase interna <em>static</em>:</p>
<pre><code class="language-java">public class CuentaBancaria {
    
    private String nombre;
    private String numeroCuenta;
    private String correoElectronico;
    private boolean bolet&#xED;n;

    // constructores/getters
    
    public static class BuilderCuentaBancaria {
        // c&#xF3;digo del builder
    }
}
</code></pre>
<p>Observa que todos los modificadores de acceso en los campos se declaran como <em>private</em>, ya que no queremos que los objetos externos accedan a ellos directamente.</p>
<p>El constructor tambi&#xE9;n es <em>private</em> para que solo el <code>Builder</code> asignado a esta clase pueda acceder a &#xE9;l. Todas las propiedades establecidas en el constructor se extraen del objeto constructor que proporcionamos como argumento.</p>
<p>Hemos definido <code>BuilderCuentaBancaria</code> en una clase interna <em>static</em>:</p>
<pre><code class="language-java">public static class BuilderCuentaBancaria {
    
    private String nombre;
    private String numeroCuenta;
    private String correoElectronico;
    private boolean boletin;
    
    public BuilderCuentaBancaria(String nombre, String numeroCuenta) {
        this.nombre = nombre;
        this.numeroCuenta = numeroCuenta;
    }

    public BuilderCuentaBancaria conCorreoElectronico(String correoElectronico) {
        this.correoElectronico = correoElectronico;
        return this;
    }

    public BuilderCuentaBancaria desearBoletin(boolean boletin) {
        this.boletin = boletin;
        return this;
    }
    
    public CuentaBancaria construir() {
        return new CuentaBancaria(this);
    }
}
</code></pre>
<p>Observa que hemos declarado el mismo conjunto de campos que contiene la clase externa. Cualquier campo obligatorio se requiere como argumentos para el constructor de la clase interna, mientras que los campos opcionales restantes se pueden especificar mediante los m&#xE9;todos establecedores.</p>
<p>Esta implementaci&#xF3;n tambi&#xE9;n admite el enfoque de dise&#xF1;o fluido al hacer que los m&#xE9;todos establecedores devuelvan el objeto builder.</p>
<p>Finalmente, el m&#xE9;todo de construcci&#xF3;n llama al constructor privado de la clase externa y se pasa a s&#xED; mismo como argumento. La <code>CuentaBancaria</code> devuelta se instanciar&#xE1; con los par&#xE1;metros establecidos por el <code>BuilderCuentaBancaria</code>.</p>
<p>Veamos un ejemplo r&#xE1;pido del patr&#xF3;n builder en acci&#xF3;n:</p>
<pre><code class="language-java">CuentaBancaria nuevaCuenta = new CuentaBancaria
  .BuilderCuentaBancaria(&quot;Toni&quot;, &quot;55318560231&quot;)
  .conCorreoElectronico(&quot;toni@montana.com&quot;)
  .desearBoletin(true)
  .construir();
</code></pre>
<h2 id="span-name6-la-palabra-clave-this-dentro-de-la-clase-intspan-6-la-palabra-clave-this-dentro-de-la-clase-interna"><span name="6-la-palabra-clave-this-dentro-de-la-clase-int"></span> <a href="#6-la-palabra-clave-this-dentro-de-la-clase-int">6.</a> La Palabra Clave <em>this</em> Dentro de la Clase Interna</h2>
<p>Tambi&#xE9;n usamos &apos;this&apos; para acceder a la instancia de la clase externa desde dentro de la clase interna:</p>
<pre><code class="language-java">public class PruebaPalabraClave {

    private String nombre;

    class EstaClaseInterna {

        boolean esClaseInterna = true;

        public EstaClaseInterna() {
            PruebaPalabraClave thisPalabraClave = PruebaPalabraClave.this;
            String cadenaExterna = PruebaPalabraClave.this.nombre;
        }
    }
}
</code></pre>
<p>Aqu&#xED;, dentro del constructor, podemos obtener una referencia a la instancia de <code>PruebaPalabraClave</code> con la llamada a <code>PruebaPalabraClave.this</code>. Incluso podemos acceder a las variables de instancia como el campo <code>PruebaPalabraClave.this.nombre</code>.</p>
<h2 id="span-name7-conclusionspan-7-conclusi%C3%B3n"><span name="7-conclusion"></span> <a href="#7-conclusion">7.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, hemos explorado la palabra clave <em>this</em> en Java en profundidad.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Herencia y Composición en Java]]></title><description><![CDATA[Herencia y composición, junto con abstracción, encapsulación y polimorfismo, son fundamentos de la programación orientada a objetos.
En este tutorial, cubriremos los conceptos básicos de herencia y composición, y nos centraremos en identificar las diferencias entre los dos tipos de relaciones.]]></description><link>https://javamagician.com/java-herencia-composicion/</link><guid isPermaLink="false">6532e9f76be40604eb515299</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Mon, 23 Oct 2023 10:15:50 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-herencia-composicion_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-herencia-composicion_600x750.png" alt="Herencia y Composici&#xF3;n en Java"><p><a href="https://javamagician.com/java-herencia/">Herencia</a> y composici&#xF3;n, junto con abstracci&#xF3;n, encapsulaci&#xF3;n y polimorfismo, son fundamentos de la <a href="https://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos?ref=javamagician.com">programaci&#xF3;n orientada a objetos</a> (POO, o en ingl&#xE9;s, <a href="https://javamagician.com/tag/oop/">OOP</a>).</p>
<p>En este tutorial, cubriremos los conceptos b&#xE1;sicos de herencia y composici&#xF3;n, y nos centraremos en identificar las diferencias entre los dos tipos de relaciones.</p>
<h2 id="span-name2-conceptos-basicos-de-la-herenciaspan-2-conceptos-b%C3%A1sicos-de-la-herencia"><span name="2-conceptos-basicos-de-la-herencia"></span> <a href="#2-conceptos-basicos-de-la-herencia">2.</a> Conceptos B&#xE1;sicos de la Herencia</h2>
<p>La herencia es un mecanismo poderoso pero a menudo sobrecargado y mal utilizado.</p>
<p>En pocas palabras, con la herencia, una clase base (tambi&#xE9;n conocida como tipo base) define el estado y el comportamiento com&#xFA;n para un tipo dado y permite que las subclases (tambi&#xE9;n conocidas como subtipos) proporcionen versiones especializadas de ese estado y comportamiento.</p>
<p>Para tener una idea clara de c&#xF3;mo trabajar con la herencia, creemos un ejemplo ingenuo: una clase base <code>Persona</code> que define los campos y m&#xE9;todos comunes para una persona, mientras que las subclases <code>Camarera</code> y <code>Actriz</code> proporcionan implementaciones adicionales y detalladas de m&#xE9;todos.</p>
<p>Aqu&#xED; est&#xE1; la clase <code>Persona</code>:</p>
<pre><code class="language-java">public class Persona {
    private final String nombre;

    // otros campos, constructores est&#xE1;ndar, getters
</code></pre>
<p>Y estas son las subclases:</p>
<pre><code class="language-java">public class Camarera extends Persona {

    public String servirEntrada(String tapa) {
        return &quot;Sirviendo una raci&#xF3;n de &quot; + tapa;
    }

    // m&#xE9;todos/constructores adicionales
}

public class Actriz extends Persona {

    public String leerGui&#xF3;n(String pel&#xED;cula) {
        return &quot;Leyendo el gui&#xF3;n de &quot; + pel&#xED;cula;
    }

    // m&#xE9;todos/constructores adicionales
</code></pre>
<p>Adem&#xE1;s, creemos una prueba unitaria para verificar que las instancias de las clases <code>Camarera</code> y <code>Actriz</code> tambi&#xE9;n son instancias de <code>Persona</code>, demostrando as&#xED; que se cumple la condici&#xF3;n &quot;es-un&quot; a nivel de tipo:</p>
<pre><code class="language-java">@Test
public void dadaInstanciaCamarera_cuandoComprobamosTipo_entoncesEsInstanciaDePersona() {
    assertThat(new Camarera(&quot;Mar&#xED;a&quot;, &quot;maria@dominio.com&quot;, 24))
        .isInstanceOf(Persona.class);
}

@Test
public void dadaInstanciaActriz_cuandoComprobamosTipo_entoncesEsInstanciaDePersona() {
    assertThat(new Actriz(&quot;Cristina&quot;, &quot;cristina@dominio.com&quot;, 35))
        .isInstanceOf(Persona.class);
}
</code></pre>
<p><strong>Es importante destacar aqu&#xED; el aspecto sem&#xE1;ntico de la herencia.</strong> Adem&#xE1;s de reutilizar la implementaci&#xF3;n de la clase <code>Persona</code>, <strong>hemos creado una relaci&#xF3;n &quot;es-un&quot; bien definida entre el tipo base</strong> <code>Persona</code> <strong>y los subtipos</strong> <code>Camarera</code> y <code>Actriz</code>. Las camareras y actrices son, efectivamente, personas.</p>
<p>Esto puede llevarnos a preguntarnos: <strong>&#xBF;en qu&#xE9; casos es apropiado utilizar la herencia?</strong></p>
<p><strong>Si los subtipos cumplen con la condici&#xF3;n &quot;es-un&quot; y principalmente proporcionan funcionalidad aditiva m&#xE1;s abajo en la jerarqu&#xED;a de clases, entonces la herencia es el camino a seguir.</strong></p>
<p>Por supuesto, la sobrescritura de m&#xE9;todos est&#xE1; permitida siempre que los m&#xE9;todos sobrescritos preserven la sustituibilidad entre el tipo base y el subtipo promovida por el <a href="https://es.wikipedia.org/wiki/Principio_de_sustituci%C3%B3n_de_Liskov?ref=javamagician.com">Principio de Sustituci&#xF3;n de Liskov</a>.</p>
<p>Adem&#xE1;s, debemos tener en cuenta que <strong>los subtipos heredan la API del tipo base</strong>, lo cual en algunos casos puede ser excesivo o simplemente indeseable.</p>
<p>De lo contrario, deber&#xED;amos usar composici&#xF3;n en su lugar.</p>
<h2 id="span-name3-herencia-en-patrones-de-dise%C3%B1ospan-3-herencia-en-patrones-de-dise%C3%B1o"><span name="3-herencia-en-patrones-de-dise&#xF1;o"></span> <a href="#3-herencia-en-patrones-de-dise%C3%B1o">3.</a> Herencia en Patrones de Dise&#xF1;o</h2>
<p>Si bien el consenso es que debemos favorecer la composici&#xF3;n sobre la herencia siempre que sea posible, existen algunos casos t&#xED;picos en los que la herencia tiene su lugar.</p>
<h3 id="span-name31-el-patron-de-supertipo-de-capaspan-31-el-patr%C3%B3n-de-supertipo-de-capa"><span name="3.1-el-patron-de-supertipo-de-capa"></span> <a href="#3.1-el-patron-de-supertipo-de-capa">3.1</a> El Patr&#xF3;n de Supertipo de Capa</h3>
<p>En este caso, <strong>utilizamos la herencia para mover el c&#xF3;digo com&#xFA;n a una clase base (el supertipo)</strong>.</p>
<p>Aqu&#xED; hay una implementaci&#xF3;n b&#xE1;sica de este patr&#xF3;n en la capa de dominio:</p>
<pre><code class="language-java">public class Entidad {
    
    protected long id;
    
    // setters
}

public class Usuario extends Entidad {
    
    // campos y m&#xE9;todos adicionales   
}
</code></pre>
<p>Podemos aplicar el mismo enfoque a las otras capas del sistema, como las capas de servicio y persistencia.</p>
<h3 id="span-name32-el-patron-de-metodo-de-plantillaspan-32-el-patr%C3%B3n-de-m%C3%A9todo-de-plantilla"><span name="3.2-el-patron-de-metodo-de-plantilla"></span> <a href="#3.2-el-patron-de-metodo-de-plantilla">3.2</a> El Patr&#xF3;n de M&#xE9;todo de Plantilla</h3>
<p>En el patr&#xF3;n de m&#xE9;todo de plantilla, podemos <strong>usar una clase base para definir las partes invariantes de un algoritmo y luego implementar las partes variantes en las subclases</strong>:</p>
<pre><code class="language-java">public abstract class ConstructorDeComputadora {
    
    public final Computadora construirComputadora() {
        agregarProcesador();
        agregarMemoria();
    }
    
    public abstract void agregarProcesador();
    
    public abstract void agregarMemoria();
}

public class ConstructorDeComputadoraEstandar extends ConstructorDeComputadora {

    @Override
    public void agregarProcesador() {
        // implementaci&#xF3;n del m&#xE9;todo
    }
    
    @Override
    public void agregarMemoria() {
        // implementaci&#xF3;n del m&#xE9;todo
    }
}
</code></pre>
<h2 id="span-name4-conceptos-basicos-de-la-composicionspan-4-conceptos-b%C3%A1sicos-de-la-composici%C3%B3n"><span name="4-conceptos-basicos-de-la-composicion"></span> <a href="#4-conceptos-basicos-de-la-composicion">4.</a> Conceptos B&#xE1;sicos de la Composici&#xF3;n</h2>
<p>La composici&#xF3;n es otro mecanismo proporcionado por la POO para reutilizar la implementaci&#xF3;n.</p>
<p>En pocas palabras, <strong>la composici&#xF3;n nos permite modelar objetos que est&#xE1;n formados por otros objetos</strong>, definiendo as&#xED; una relaci&#xF3;n &quot;tiene-un&quot; entre ellos.</p>
<p>Adem&#xE1;s, <strong>la composici&#xF3;n es la forma m&#xE1;s fuerte de <a href="https://es.wikipedia.org/wiki/Composici%C3%B3n_de_objetos?ref=javamagician.com">asociaci&#xF3;n</a></strong>, lo que significa que <strong>los objetos que componen o est&#xE1;n contenidos por un objeto se destruyen tambi&#xE9;n cuando se destruye ese objeto</strong>.</p>
<p>Para comprender mejor c&#xF3;mo funciona la composici&#xF3;n, supongamos que necesitamos trabajar con objetos que representan computadoras.</p>
<p>Una computadora est&#xE1; compuesta por diferentes componentes, como el microprocesador, la memoria, una tarjeta de sonido y m&#xE1;s, por lo que podemos modelar tanto la computadora como cada uno de sus componentes como clases individuales.</p>
<p>As&#xED; es como podr&#xED;a verse una implementaci&#xF3;n simple de la clase <code>Computadora</code>:</p>
<pre><code class="language-java">public class Computadora {

    private Procesador procesador;
    private Memoria memoria;
    private TarjetaDeSonido tarjetaDeSonido;

    // getters/setters/constructores est&#xE1;ndar
    
    public Optional&lt;TarjetaDeSonido&gt; getTarjetaDeSonido() {
        return Optional.ofNullable(tarjetaDeSonido);
    }
}
</code></pre>
<p>Las siguientes clases modelan un microprocesador, la memoria y una tarjeta de sonido (las interfaces se omiten por brevedad):</p>
<pre><code class="language-java">public class ProcesadorEstandar implements Procesador {

    private String modelo;
    
    // getters/setters est&#xE1;ndar
}

public class MemoriaEstandar implements Memoria {
    
    private String marca;
    private String capacidad;
    
    // constructores est&#xE1;ndar, getters, toString
}

public class TarjetaDeSonidoEstandar implements TarjetaDeSonido {
    
    private String marca;

    // constructores est&#xE1;ndar, getters, toString
}
</code></pre>
<p>Es f&#xE1;cil entender las motivaciones detr&#xE1;s de dar prioridad a la composici&#xF3;n sobre la herencia. <strong>En todos los escenarios en los que es posible establecer una relaci&#xF3;n sem&#xE1;nticamente correcta de &quot;tiene-un&quot; entre una clase dada y otras, la composici&#xF3;n es la elecci&#xF3;n correcta.</strong></p>
<p>En el ejemplo anterior, <code>Computadora</code> cumple con la condici&#xF3;n de &quot;tiene-un&quot; con las clases que modelan sus componentes.</p>
<p>Tambi&#xE9;n es importante se&#xF1;alar que en este caso, <strong>el objeto <code>Computadora</code> tiene la propiedad de los objetos contenidos solo si los objetos no se pueden reutilizar en otra <code>Computadora</code></strong>. Si pueden, estar&#xED;amos utilizando agregaci&#xF3;n en lugar de composici&#xF3;n, donde la propiedad no est&#xE1; impl&#xED;cita.</p>
<h2 id="span-name5-composicion-sin-abstraccionspan-5-composici%C3%B3n-sin-abstracci%C3%B3n"><span name="5-composicion-sin-abstraccion"></span> <a href="#5-composicion-sin-abstraccion">5.</a> Composici&#xF3;n Sin Abstracci&#xF3;n</h2>
<p>Alternativamente, podr&#xED;amos haber definido la relaci&#xF3;n de composici&#xF3;n codificando las dependencias de la clase <code>Computadora</code> en lugar de declararlas en el constructor:</p>
<pre><code class="language-java">public class Computadora {

    private ProcesadorEstandar procesador
        = new ProcesadorEstandar(&quot;Intel I3&quot;);
    private MemoriaEstandar memoria
        = new MemoriaEstandar(&quot;Kingston&quot;, &quot;1TB&quot;);
    
    // campos/m&#xE9;todos adicionales
}
</code></pre>
<p><strong>Por supuesto, esto ser&#xED;a un dise&#xF1;o r&#xED;gido y fuertemente acoplado, ya que har&#xED;amos que la clase <code>Computadora</code> dependiera fuertemente de implementaciones espec&#xED;ficas de <code>Procesador</code> y <code>Memoria</code></strong>.</p>
<p>No estar&#xED;amos aprovechando el nivel de abstracci&#xF3;n proporcionado por las interfaces y la <a href="https://es.wikipedia.org/wiki/Inyecci%C3%B3n_de_dependencias?ref=javamagician.com">inyecci&#xF3;n de dependencias</a>.</p>
<p>Con el dise&#xF1;o inicial basado en interfaces, obtenemos un dise&#xF1;o con bajo acoplamiento, que tambi&#xE9;n es m&#xE1;s f&#xE1;cil de probar.</p>
<h2 id="span-name6-conclusionspan-6-conclusi%C3%B3n"><span name="6-conclusion"></span> <a href="#6-conclusion">6.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, aprendimos los fundamentos de la herencia y la composici&#xF3;n en Java, y exploramos en profundidad las diferencias entre los dos tipos de relaciones (&quot;es-un&quot; vs. &quot;tiene-un&quot;).</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Herencia en Java]]></title><description><![CDATA[La herencia, nos permite reutilizar código existente o extender un tipo de clase existente. En este artículo, comenzaremos con la necesidad de la herencia, pasando a cómo funciona la herencia con clases e interfaces.]]></description><link>https://javamagician.com/java-herencia/</link><guid isPermaLink="false">653057906be40604eb5151bc</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Thu, 19 Oct 2023 08:47:25 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-herencia_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-herencia_600x750.png" alt="Herencia en Java"><p>Uno de los principios fundamentales de la Programaci&#xF3;n Orientada a Objetos: <strong>la herencia, nos permite reutilizar c&#xF3;digo existente o extender un tipo de clase existente.</strong></p>
<p>En pocas palabras, en Java, una clase puede heredar de otra clase y m&#xFA;ltiples interfaces, mientras que una interfaz puede heredar de otras interfaces.</p>
<p>En este art&#xED;culo, comenzaremos con la necesidad de la herencia, pasando a c&#xF3;mo funciona la herencia con clases e interfaces.</p>
<p>Luego, cubriremos c&#xF3;mo los nombres de variables/m&#xE9;todos y los modificadores de acceso afectan a los miembros que se heredan.</p>
<p>Y al final, veremos qu&#xE9; significa heredar un tipo.</p>
<h2 id="span-name2-la-necesidad-de-la-herenciaspan-2-la-necesidad-de-la-herencia"><span name="2-la-necesidad-de-la-herencia"></span> <a href="#2-la-necesidad-de-la-herencia">2.</a> La Necesidad de la Herencia</h2>
<p>Imagina, como fabricante de coches, que ofreces m&#xFA;ltiples modelos de coches a tus clientes. Aunque diferentes modelos de coches pueden ofrecer diferentes caracter&#xED;sticas como un techo corredizo o ventanas a prueba de balas, todos incluir&#xED;an componentes y caracter&#xED;sticas comunes, como el motor y las ruedas.</p>
<p>Tiene sentido <strong>crear un dise&#xF1;o b&#xE1;sico y extenderlo para crear sus versiones especializadas</strong>, en lugar de dise&#xF1;ar cada modelo de coche por separado, desde cero.</p>
<p>De manera similar, con la herencia, podemos crear una clase con caracter&#xED;sticas y comportamientos b&#xE1;sicos y crear sus versiones especializadas mediante la creaci&#xF3;n de clases que heredan esta clase base. De la misma manera, las interfaces pueden extender interfaces existentes.</p>
<p>Notaremos el uso de varios t&#xE9;rminos para referirse a un tipo que es heredado por otro tipo, espec&#xED;ficamente:</p>
<ul>
<li><strong>un tipo base tambi&#xE9;n se llama tipo super o padre</strong></li>
<li><strong>un tipo derivado se denomina tipo extendido, subtipo o hijo</strong></li>
</ul>
<h2 id="span-name3-herencia-de-clasespan-3-herencia-de-clase"><span name="3-herencia-de-clase"></span> <a href="#3-herencia-de-clase">3.</a> Herencia de Clase</h2>
<h3 id="span-name31-extender-una-clasespan-31-extender-una-clase"><span name="3.1-extender-una-clase"></span> <a href="#3.1-extender-una-clase">3.1.</a> Extender una Clase</h3>
<p>Una clase puede heredar de otra clase y definir miembros adicionales.</p>
<p>Comencemos definiendo una clase base <code>Coche</code>:</p>
<pre><code class="language-java">public class Coche {
    int ruedas;
    String modelo;
    void arrancar() {
        // Verificar partes esenciales
    }
}
</code></pre>
<p>La clase <code>CocheBlindado</code> puede heredar los miembros de la clase <code>Coche</code> <strong>usando la palabra clave <em>extends</em> en su declaraci&#xF3;n</strong>:</p>
<pre><code class="language-java">public class CocheBlindado extends Coche {
    int ventanasAntibalas;
    void arrancarConControlRemoto() {
	// este veh&#xED;culo se puede arrancar con un control remoto
    }
}
</code></pre>
<p>Ahora podemos decir que la clase <code>CocheBlindado</code> es una subclase de <code>Coche</code>, y esta &#xFA;ltima es una superclase de <code>CocheBlindado</code>.</p>
<p><strong>Las clases en Java admiten herencia simple</strong>; la clase <code>CocheBlindado</code> no puede extender m&#xFA;ltiples clases.</p>
<p>Adem&#xE1;s, ten en cuenta que en ausencia de una palabra clave <em>extends</em>, una clase hereda impl&#xED;citamente la clase <code>java.lang.Object</code>.</p>
<p><strong>Una subclase hereda los miembros <em>protected</em> y <em>public</em> no est&#xE1;ticos de la superclase</strong>. Adem&#xE1;s, los miembros con acceso <em>default</em> (<em>package-private</em>) se heredan si las dos clases est&#xE1;n en el mismo paquete.</p>
<p>Por otro lado, los miembros <em>private</em> y <em>static</em> de una clase no se heredan.</p>
<h3 id="span-name32-acceso-a-miembros-padre-desde-una-clase-hijaspan-32-acceso-a-miembros-padre-desde-una-clase-hija"><span name="3.2-acceso-a-miembros-padre-desde-una-clase-hija"></span> <a href="#3.2-acceso-a-miembros-padre-desde-una-clase-hija">3.2.</a> Acceso a Miembros Padre desde una Clase Hija</h3>
<p>Para acceder a propiedades o m&#xE9;todos heredados, simplemente podemos usarlos directamente:</p>
<pre><code class="language-java">public class CocheBlindado extends Coche {
    public String registrarModelo() {
        return modelo;
    }
</code></pre>
<p>Ten en cuenta que no necesitamos una referencia a la superclase para acceder a sus miembros.</p>
<h2 id="span-name4-herencia-de-interfazspan-4-herencia-de-interfaz"><span name="4-herencia-de-interfaz"></span> <a href="#4-herencia-de-interfaz">4.</a> Herencia de Interfaz</h2>
<h3 id="span-name41-implementar-multiples-interfacesspan-41-implementar-m%C3%BAltiples-interfaces"><span name="4.1-implementar-multiples-interfaces"></span> <a href="#4.1-implementar-multiples-interfaces">4.1.</a> Implementar M&#xFA;ltiples Interfaces</h3>
<p><strong>Aunque las clases pueden heredar solo de una clase, pueden implementar m&#xFA;ltiples interfaces.</strong></p>
<p>Imagina que el <code>CocheBlindado</code> que definimos en la secci&#xF3;n anterior es necesario para un superesp&#xED;a. Entonces, la compa&#xF1;&#xED;a fabricante de coches pens&#xF3; en agregar funcionalidades de vuelo y flotaci&#xF3;n:</p>
<pre><code class="language-java">public interface Flotable {
    void flotarEnAgua();
}

public interface Volable {
    void volar();
}

public class CocheBlindado extends Coche implements Flotable, Volable {
    public void flotarEnAgua() {
        System.out.println(&quot;&#xA1;Puedo flotar!&quot;);
    }

    public void volar() {
        System.out.println(&quot;&#xA1;Puedo volar!&quot;);
    }
}
</code></pre>
<p>En el ejemplo anterior, notamos el uso de la palabra clave <em>implements</em> para heredar de una interfaz.</p>
<h3 id="span-name42-problemas-con-la-herencia-multiplespan-42-problemas-con-la-herencia-m%C3%BAltiple"><span name="4.2-problemas-con-la-herencia-multiple"></span> <a href="#4.2-problemas-con-la-herencia-multiple">4.2.</a> Problemas con la Herencia M&#xFA;ltiple</h3>
<p><strong>Java permite la herencia m&#xFA;ltiple mediante interfaces.</strong></p>
<p>Hasta Java 7, esto no era un problema. Las interfaces solo pod&#xED;an definir m&#xE9;todos <em>abstract</em>, es decir, m&#xE9;todos sin ninguna implementaci&#xF3;n. Entonces, si una clase implementaba m&#xFA;ltiples interfaces con la misma firma de m&#xE9;todo, no era un problema. La clase que implementaba finalmente solo ten&#xED;a un m&#xE9;todo que implementar.</p>
<p>Veamos c&#xF3;mo esta ecuaci&#xF3;n simple cambi&#xF3; con la introducci&#xF3;n de m&#xE9;todos <em>default</em> en las interfaces con Java 8.</p>
<p><strong>A partir de Java 8, las interfaces pod&#xED;an optar por definir implementaciones <em>default</em> para sus m&#xE9;todos</strong> (una interfaz todav&#xED;a puede definir m&#xE9;todos <em>abstract</em>). Esto significa que si una clase implementa m&#xFA;ltiples interfaces que definen m&#xE9;todos con la misma firma, la clase hija heredar&#xED;a implementaciones separadas. Esto suena complejo y no est&#xE1; permitido.</p>
<p><strong>Java no permite la herencia de m&#xFA;ltiples implementaciones de los mismos m&#xE9;todos definidos en interfaces separadas.</strong></p>
<p>Aqu&#xED; tienes un ejemplo:</p>
<pre><code class="language-java">public interface Flotable {
    default void reparar() {
    	System.out.println(&quot;Reparando objeto flotante&quot;);	
    }
}

public interface Volable {
    default void reparar() {
    	System.out.println(&quot;Reparando objeto volador&quot;);	
    }
}

public class CocheBlindado extends Coche implements Flotable, Volable {
    // esto no se compilar&#xE1;
}
</code></pre>
<p>Si deseamos implementar ambas interfaces, tendremos que sobrescribir el m&#xE9;todo <code>reparar</code>.</p>
<p>Si las interfaces en los ejemplos anteriores definen variables con el mismo nombre, por ejemplo, <code>duracion</code>, no podemos acceder a ellas sin preceder el nombre de la variable con el nombre de la interfaz:</p>
<pre><code class="language-java">public interface Flotable {
    int duracion = 10;
}

public interface Volable {
    int duracion = 20;
}

public class CocheBlindado extends Coche implements Flotable, Volable {
 
    public void unMetodo() {
    	System.out.println(duracion); // no se compilar&#xE1;
    	System.out.println(Flotable.duracion); // muestra 10
    	System.out.println(Volable.duracion); // muestra 20
    }
}
</code></pre>
<h3 id="span-name43-interfaces-que-extienden-otras-interfacesspan-43-interfaces-que-extienden-otras-interfaces"><span name="4.3-interfaces-que-extienden-otras-interfaces"></span> <a href="#4.3-interfaces-que-extienden-otras-interfaces">4.3.</a> Interfaces que Extienden Otras Interfaces</h3>
<p>Una interfaz puede extender m&#xFA;ltiples interfaces. Aqu&#xED; tienes un ejemplo:</p>
<pre><code class="language-java">public interface Flotable {
    void flotarEnAgua();
}

interface Volable {
    void volar();
}

public interface NaveEspacial extends Flotable, Volable {
    void controlRemoto();
}
</code></pre>
<p>Una interfaz hereda otras interfaces usando la palabra clave <em>extends</em>. Las clases usan la palabra clave <em>implements</em> para heredar una interfaz.</p>
<h2 id="span-name5-heredar-tipospan-5-heredar-tipo"><span name="5-heredar-tipo"></span> <a href="#5-heredar-tipo">5.</a> Heredar Tipo</h2>
<p>Cuando una clase hereda de otra clase o interfaces, adem&#xE1;s de heredar sus miembros, tambi&#xE9;n hereda su tipo. Esto tambi&#xE9;n se aplica a una interfaz que hereda otras interfaces.</p>
<p>Este es un concepto muy poderoso que permite a los desarrolladores <strong>programar a una interfaz (clase base o interfaz)</strong>, en lugar de programar a sus implementaciones.</p>
<p>Por ejemplo, imagina una situaci&#xF3;n en la que una organizaci&#xF3;n mantiene una lista de los coches propiedad de sus empleados. Por supuesto, todos los empleados pueden poseer diferentes modelos de coches. Entonces, &#xBF;c&#xF3;mo podemos referirnos a diferentes instancias de coches? Aqu&#xED; est&#xE1; la soluci&#xF3;n:</p>
<pre><code class="language-java">public class Empleado {
    private String nombre;
    private Coche coche;
    
    // constructor est&#xE1;ndar
}
</code></pre>
<p>Dado que todas las clases derivadas de <code>Coche</code> heredan el tipo <code>Coche</code>, las instancias de clases derivadas se pueden referir mediante una variable de tipo <code>Coche</code>:</p>
<pre><code class="language-java">Empleado e1 = new Empleado(&quot;Toni&quot;, new CocheBlindado());
Empleado e2 = new Empleado(&quot;Paco&quot;, new CocheDeCarreras());
Empleado e3 = new Empleado(&quot;Rub&#xE9;n&quot;, new Ferrari());
</code></pre>
<h2 id="span-name6-miembros-ocultos-de-la-clasespan-6-miembros-ocultos-de-la-clase"><span name="6-miembros-ocultos-de-la-clase"></span> <a href="#6-miembros-ocultos-de-la-clase">6.</a> Miembros Ocultos de la Clase</h2>
<h3 id="span-name61-miembros-de-instancia-ocultosspan-61-miembros-de-instancia-ocultos"><span name="6.1-miembros-de-instancia-ocultos"></span> <a href="#6.1-miembros-de-instancia-ocultos">6.1.</a> Miembros de Instancia Ocultos</h3>
<p><strong>&#xBF;Qu&#xE9; sucede si tanto la superclase como la subclase definen una variable o m&#xE9;todo con el mismo nombre?</strong> No te preocupes, a&#xFA;n podemos acceder a ambos. Sin embargo, debemos hacer nuestro intento claro para Java, prefijando la variable o el m&#xE9;todo con las palabras clave <em>this</em> o <em>super</em>.</p>
<p>La palabra clave <em>this</em> se refiere a la instancia en la que se utiliza. La palabra clave <em>super</em> se refiere a la instancia de la clase padre:</p>
<pre><code class="language-java">public class CocheBlindado extends Coche {
    private String modelo;
    public String obtenerUnValor() {
    	return super.modelo;   // devuelve el valor de modelo definido en la clase base Coche
    	// return this.modelo;   // devolver&#xE1; el valor de modelo definido en CocheBlindado
    	// return modelo;   // devolver&#xE1; el valor de modelo definido en CocheBlindado
    }
}
</code></pre>
<p>Muchos desarrolladores usan las palabras clave <em>this</em> y <em>super</em> para indicar expl&#xED;citamente a qu&#xE9; variable o m&#xE9;todo se refieren. Sin embargo, usarlas con todos los miembros puede hacer que nuestro c&#xF3;digo parezca desordenado.</p>
<h3 id="span-name62-miembros-static-ocultosspan-62-miembros-static-ocultos"><span name="6.2-miembros-static-ocultos"></span> <a href="#6.2-miembros-static-ocultos">6.2.</a> Miembros <em>static</em> Ocultos</h3>
<p><strong>&#xBF;Qu&#xE9; sucede cuando nuestra clase base y las subclases definen variables y m&#xE9;todos est&#xE1;ticos con el mismo nombre?</strong> &#xBF;Podemos acceder a un miembro <em>static</em> desde la clase base en la clase derivada, de la misma manera en que lo hacemos para las variables de instancia?</p>
<p>Averig&#xFC;&#xE9;moslo usando un ejemplo:</p>
<pre><code class="language-java">public class Coche {
    public static String mensaje() {
        return &quot;Coche&quot;;
    }
}

public class CocheBlindado extends Coche {
    public static String mensaje() {
        return super.mensaje(); // esto no se compilar&#xE1;.
    }
}
</code></pre>
<p>No, no podemos. Los miembros est&#xE1;ticos pertenecen a una clase y no a las instancias. Entonces no podemos usar la palabra clave <em>super</em> no est&#xE1;tica en <code>mensaje()</code>.</p>
<p>Dado que los miembros est&#xE1;ticos pertenecen a una clase, podemos modificar la llamada anterior de la siguiente manera:</p>
<pre><code class="language-java">return Coche.mensaje();
</code></pre>
<p>Considera el siguiente ejemplo en el que tanto la clase base como la clase derivada definen un m&#xE9;todo <em>static</em> <code>mensaje()</code> con la misma firma:</p>
<pre><code class="language-java">public class Coche {
    public static String mensaje() {
        return &quot;Coche&quot;;
    }
}

public class CocheBlindado extends Coche {
    public static String mensaje() {
        return &quot;CocheBlindado&quot;;
    }
}
</code></pre>
<p>As&#xED; es como podemos llamarlos:</p>
<pre><code class="language-java">Coche primero = new CocheBlindado();
CocheBlindado segundo = new CocheBlindado();
</code></pre>
<p>Para el c&#xF3;digo anterior, <code>primero.mensaje()</code> mostrar&#xE1; <code>Coche</code> y <code>segundo.mensaje()</code> mostrar&#xE1; <code>CocheBlindado</code>. El mensaje est&#xE1;tico que se llama depende del tipo de variable utilizada para referirse a la instancia de <code>CocheBlindado</code>.</p>
<h3 id="span-name7-conclusionspan-7-conclusi%C3%B3n"><span name="7-conclusion"></span> <a href="#7-conclusion">7.</a> Conclusi&#xF3;n</h3>
<p>En este art&#xED;culo, cubrimos un aspecto fundamental del lenguaje Java: la herencia.</p>
<p>Vimos c&#xF3;mo Java admite la herencia simple con clases y la herencia m&#xFA;ltiple con interfaces, y discutimos las complejidades de c&#xF3;mo funciona este mecanismo en el lenguaje.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Métodos private en Interfaces de Java]]></title><description><![CDATA[A partir de Java 9, se pueden agregar métodos privados a las interfaces en Java. En este breve tutorial, discutiremos cómo podemos definir estos métodos y sus beneficios]]></description><link>https://javamagician.com/java-metodos-privados-en-interfaces/</link><guid isPermaLink="false">6527e9c0e9daa8aba6216b67</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Thu, 12 Oct 2023 12:50:48 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<p><strong>A partir de Java 9, se pueden agregar <a href="http://openjdk.java.net/jeps/213?ref=javamagician.com">m&#xE9;todos privados</a> a las interfaces en Java.</strong> En este breve tutorial, discutiremos c&#xF3;mo podemos definir estos m&#xE9;todos y sus beneficios.</p>
<h2 id="span-name2-definir-metodos-private-en-las-interfacesspan-2-definir-m%C3%A9todos-private-en-las-interfaces"><span name="2-definir-metodos-private-en-las-interfaces"></span> <a href="#2-definir-metodos-private-en-las-interfaces">2.</a> Definir M&#xE9;todos <em>private</em> en las Interfaces</h2>
<p>Los m&#xE9;todos <em>private</em> se pueden implementar de manera est&#xE1;tica o no est&#xE1;tica. Esto significa que en una interfaz podemos crear m&#xE9;todos <em>private</em> para encapsular el c&#xF3;digo de las firmas de m&#xE9;todos p&#xFA;blicos <em>default</em> y <em>static</em>.</p>
<p>Primero, veamos c&#xF3;mo podemos utilizar m&#xE9;todos privados a partir de m&#xE9;todos <em>default</em> de la interfaz:</p>
<pre><code class="language-java">public interface Foo {

    default void bar() {
        System.out.print(&quot;Hola&quot;);
        baz();
    }

    private void baz() {
        System.out.println(&quot; mundo!&quot;);
    }
}
</code></pre>
<p><code>bar()</code> es capaz de utilizar el m&#xE9;todo privado <code>baz()</code> llam&#xE1;ndolo desde su m&#xE9;todo predeterminado.</p>
<p>A continuaci&#xF3;n, agreguemos un m&#xE9;todo privado definido de manera est&#xE1;tica a nuestra interfaz <code>Foo</code>:</p>
<pre><code class="language-java">public interface Foo {

    static void buzz() {
        System.out.print(&quot;Hola&quot;);
        staticBaz();
    }

    private static void staticBaz() {
        System.out.println(&quot; mundo est&#xE1;tico!&quot;);
    }
}
</code></pre>
<p>Dentro de la interfaz, otros m&#xE9;todos definidos de manera est&#xE1;tica pueden hacer uso de estos m&#xE9;todos privados y est&#xE1;ticos.</p>
<p>Finalmente, llamemos a los m&#xE9;todos <em>default</em> y <em>static</em> definidos desde una clase concreta:</p>
<pre><code class="language-java">public class FooPersonalizado implements Foo {

    public static void main(String... args) {
        Foo fooPersonalizado = new FooPersonalizado();
        fooPersonalizado.bar();
        Foo.buzz();
    }
}
</code></pre>
<p>La salida es la cadena <code>Hola mundo!</code> desde la llamada al m&#xE9;todo <code>bar()</code> y <code>Hola mundo est&#xE1;tico!</code> desde la llamada al m&#xE9;todo <code>buzz()</code>.</p>
<h2 id="span-name3-beneficios-de-los-metodos-private-en-las-interfacesspan-3-beneficios-de-los-m%C3%A9todos-private-en-las-interfaces"><span name="3-beneficios-de-los-metodos-private-en-las-interfaces"></span> <a href="#3-beneficios-de-los-metodos-private-en-las-interfaces">3.</a> Beneficios de los M&#xE9;todos <em>private</em> en las Interfaces</h2>
<p>Hablemos de los beneficios de los m&#xE9;todos privados ahora que los hemos definido.</p>
<p>Como se mencion&#xF3; en la secci&#xF3;n anterior, las interfaces pueden utilizar m&#xE9;todos privados para ocultar detalles de la implementaci&#xF3;n de las clases que implementan la interfaz. Como resultado, uno de los principales beneficios de tenerlos en las interfaces es la encapsulaci&#xF3;n.</p>
<p>Otro beneficio es (como ocurre con los m&#xE9;todos privados en general) que hay menos duplicaci&#xF3;n y m&#xE1;s c&#xF3;digo reutilizable agregado a las interfaces para m&#xE9;todos con funcionalidad similar.</p>
<h2 id="span-name4-conclusionspan-4-conclusi%C3%B3n"><span name="4-conclusion"></span> <a href="#4-conclusion">4.</a> Conclusi&#xF3;n</h2>
<p>En este tutorial, hemos cubierto c&#xF3;mo definir m&#xE9;todos privados dentro de una interfaz y c&#xF3;mo podemos utilizarlos desde contextos tanto est&#xE1;ticos como no est&#xE1;ticos.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Interfaces en Java]]></title><description><![CDATA[En este tutorial, vamos a hablar sobre las interfaces en Java. También veremos cómo Java las utiliza para implementar polimorfismo y la herencia múltiple.]]></description><link>https://javamagician.com/java-interfaces/</link><guid isPermaLink="false">65195489e9daa8aba6216768</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Thu, 12 Oct 2023 11:49:20 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-interfaces_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-interfaces_600x750.png" alt="Interfaces en Java"><p>En este tutorial, vamos a hablar sobre las interfaces en Java. Tambi&#xE9;n veremos c&#xF3;mo Java las utiliza para implementar polimorfismo y la herencia m&#xFA;ltiple.</p>
<h2 id="span-name2-que-son-las-interfaces-en-javaspan-2-%C2%BFqu%C3%A9-son-las-interfaces-en-java"><span name="2-que-son-las-interfaces-en-java"></span> <a href="#2-que-son-las-interfaces-en-java">2.</a> &#xBF;Qu&#xE9; Son las Interfaces en Java?</h2>
<p>En Java, una interfaz es un tipo abstracto que contiene una colecci&#xF3;n de m&#xE9;todos y variables constantes. Es uno de los conceptos fundamentales en Java y <strong>se utiliza para lograr la <a href="https://javamagician.com/java-clases-abstractas/">abstracci&#xF3;n</a>, <a href="https://javamagician.com/java-polimorfismo/">polimorfismo</a> y la herencia m&#xFA;ltiple.</strong></p>
<p>Veamos un ejemplo simple de una interfaz en Java:</p>
<pre><code class="language-java">public interface Electronico {

    // Variable constante
    String LED = &quot;LED&quot;;

    // M&#xE9;todo abstracto
    int getConsumoDeElectricidad();

    // M&#xE9;todo est&#xE1;tico
    static boolean esEficienteDesdeElPuntoDeVistaEnergetico(String tipoElectronico) {
        if (tipoElectronico.equals(LED)) {
            return true;
        }
        return false;
    }

    // M&#xE9;todo predeterminado
    default void imprimirDescripcion() {
        System.out.println(&quot;Descripci&#xF3;n Electr&#xF3;nica&quot;);
    }
}
</code></pre>
<p>Podemos implementar una interfaz en una clase Java utilizando la palabra clave <em>implements</em>.</p>
<p>A continuaci&#xF3;n, creemos tambi&#xE9;n una clase <code>Computadora</code> que implemente la interfaz <code>Electronico</code> que acabamos de crear:</p>
<pre><code class="language-java">public class Computadora implements Electronico {

    @Override
    public int getConsumoDeElectricidad() {
        return 1000;
    }
}
</code></pre>
<h3 id="span-name2-1-reglas-para-crear-interfacesspan-21-reglas-para-crear-interfaces"><span name="2-1-reglas-para-crear-interfaces"></span> <a href="#2-1-reglas-para-crear-interfaces">2.1</a> Reglas para Crear Interfaces</h3>
<p>En una interfaz, se nos permite usar:</p>
<ul>
<li><strong><a href="https://javamagician.com/basicos/java-palabra-clave-final/">Variables constantes</a></strong></li>
<li><strong><a href="https://javamagician.com/java-clases-abstractas/">M&#xE9;todos abstract</a></strong></li>
<li><strong><a href="https://javamagician.com/java-palabra-clave-static/">M&#xE9;todos static</a></strong></li>
<li><strong><a href="https://javamagician.com/java-metodos-static-default/">M&#xE9;todos default</a></strong></li>
</ul>
<p>Tambi&#xE9;n debemos recordar que:</p>
<ul>
<li>No podemos instanciar interfaces directamente.</li>
<li>Una interfaz puede estar vac&#xED;a, sin m&#xE9;todos ni variables.</li>
<li>No podemos usar la palabra clave <em>final</em> en la definici&#xF3;n de la interfaz, ya que dar&#xE1; como resultado un error de compilaci&#xF3;n.</li>
<li>Todas las declaraciones de interfaz deben tener el modificador de acceso <em>public</em> o <em>default</em>; el modificador <em>abstract</em> se agregar&#xE1; autom&#xE1;ticamente por el compilador.</li>
<li>Un m&#xE9;todo de interfaz no puede ser <em>protected</em> o <em>final</em>.</li>
<li>Hasta Java 9, los m&#xE9;todos de interfaz no pod&#xED;an ser privados; sin embargo, Java 9 introdujo la posibilidad de definir <strong><a href="https://javamagician.com/java-metodos-privados-en-interfaces/">m&#xE9;todos privados en interfaces</a></strong>.</li>
<li>Las variables de interfaz son <em>public</em>, <em>static</em> y <em>final</em> por definici&#xF3;n; no se nos permite cambiar su visibilidad.</li>
</ul>
<h2 id="span-name3-que-podemos-lograr-usandolasspan-3-%C2%BFqu%C3%A9-podemos-lograr-us%C3%A1ndolas"><span name="3-que-podemos-lograr-usandolas"></span> <a href="#3-que-podemos-lograr-usandolas">3.</a> &#xBF;Qu&#xE9; Podemos Lograr Us&#xE1;ndolas?</h2>
<h3 id="span-name3-1-funcionalidad-de-comportamientospan-31-funcionalidad-de-comportamiento"><span name="3-1-funcionalidad-de-comportamiento"></span> <a href="#3-1-funcionalidad-de-comportamiento">3.1</a> Funcionalidad de Comportamiento</h3>
<p>Utilizamos interfaces para agregar cierta funcionalidad de comportamiento que puede ser utilizada por clases no relacionadas. Por ejemplo, <code>Comparable</code>, <code>Comparator</code> y <code>Cloneable</code> son interfaces de Java que pueden ser implementadas por clases no relacionadas. A continuaci&#xF3;n, se muestra un ejemplo de la interfaz <code>Comparator</code> que se utiliza para comparar dos instancias de la clase <code>Empleado</code>:</p>
<pre><code class="language-java">public class Empleado {

    private double salario;

    public double getSalario() {
        return salario;
    }

    public void setSalario(double salario) {
        this.salario = salario;
    }
}

public class ComparadorDeSalarioEmpleado implements Comparator&lt;Empleado&gt; {

    @Override
    public int compare(Empleado empleadoA, Empleado empleadoB) {
        if (empleadoA.getSalario() &lt; empleadoB.getSalario()) {
            return -1;
        } else if (empleadoA.getSalario() &gt; empleadoB.getSalario()) { 
            return 1;
        } else {
            return 0;
        }
    }
}
</code></pre>
<h3 id="span-name3-2-herencia-multiplespan-32-herencia-m%C3%BAltiple"><span name="3-2-herencia-multiple"></span> <a href="#3-2-herencia-multiple">3.2</a> Herencia M&#xFA;ltiple</h3>
<p>Las clases Java admiten la herencia singular. Sin embargo, mediante el uso de interfaces, tambi&#xE9;n podemos implementar la herencia m&#xFA;ltiple.</p>
<p>Por ejemplo, en el siguiente ejemplo, notamos que la clase <code>Coche</code> implementa las interfaces <code>Volar</code> y <code>Transformar</code>. Al hacerlo, hereda los m&#xE9;todos <code>volar</code> y <code>transformar</code>:</p>
<pre><code class="language-java">public interface Transformar {
    void transformar();
}

public interface Volar {
    void volar();
}

public class Coche implements Volar, Transformar {

    @Override
    public void volar() {
        System.out.println(&quot;&#xA1;Puedo Volar!&quot;);
    }

    @Override
    public void transformar() {
        System.out.println(&quot;&#xA1;Puedo Transformarme!&quot;);
    }
}
</code></pre>
<h3 id="span-name3-3-polimorfismospan-33-polimorfismo"><span name="3-3-polimorfismo"></span> <a href="#3-3-polimorfismo">3.3</a> Polimorfismo</h3>
<p>Comencemos haciendo la pregunta: &#xBF;qu&#xE9; es el <a href="https://javamagician.com/java-polimorfismo/">polimorfismo</a>? Es la capacidad de un objeto para tomar diferentes formas durante la ejecuci&#xF3;n. Para ser m&#xE1;s espec&#xED;ficos, es la ejecuci&#xF3;n del m&#xE9;todo sobrescrito que est&#xE1; relacionado con un tipo de objeto espec&#xED;fico en tiempo de ejecuci&#xF3;n.</p>
<p><strong>En Java, podemos lograr el polimorfismo utilizando interfaces</strong>. Por ejemplo, la interfaz <code>Forma</code> puede tomar diferentes formas: puede ser un <code>Circulo</code> o un <code>Cuadrado</code>.</p>
<p>Comencemos definiendo la interfaz <code>Forma</code>:</p>
<pre><code class="language-java">public interface Forma {
    String nombre();
}
</code></pre>
<p>Ahora tambi&#xE9;n creemos la clase <code>Circulo</code>:</p>
<pre><code class="language-java">public class C&#xED;rculo implements Forma {

    @Override
    public String nombre() {
        return &quot;C&#xED;rculo&quot;;
    }
}
</code></pre>
<p>Y tambi&#xE9;n la clase <code>Cuadrado</code>:</p>
<pre><code class="language-java">public class Cuadrado implements Forma {

    @Override
    public String nombre() {
        return &quot;Cuadrado&quot;;
    }
}

</code></pre>
<p>Finalmente, es hora de ver el polimorfismo en acci&#xF3;n utilizando nuestra interfaz <code>Forma</code> y sus implementaciones. Creemos algunas instancias de objetos <code>Forma</code>, agr&#xE9;guelas a una <code>List</code> y, finalmente, imprima sus nombres en un bucle:</p>
<pre><code class="language-java">List&lt;Forma&gt; formas = new ArrayList&lt;&gt;();
Forma formaCirculo =

 new C&#xED;rculo();
Forma formaCuadrado = new Cuadrado();

formas.add(formaCirculo);
formas.add(formaCuadrado);

for (Forma forma : formas) {
    System.out.println(forma.nombre());
}
</code></pre>
<h2 id="span-name4-metodos-default-en-interfacesspan-4-m%C3%A9todos-default-en-interfaces"><span name="4-metodos-default-en-interfaces"></span> <a href="#4-metodos-default-en-interfaces">4.</a> M&#xE9;todos <em>default</em> en Interfaces</h2>
<p>Las interfaces tradicionales en Java 7 y anteriores no ofrecen compatibilidad inversa.</p>
<p>Lo que esto significa es que <strong>si tienes c&#xF3;digo heredado escrito en Java 7 o anterior, y decides agregar un m&#xE9;todo <em>abstract</em> a una interfaz existente, entonces todas las clases que implementen esa interfaz deben sobrescribir el nuevo m&#xE9;todo <em>abstract</em></strong>. De lo contrario, el c&#xF3;digo se romper&#xE1;.</p>
<p><strong>Java 8 resolvi&#xF3; este problema al introducir el m&#xE9;todo <em>default</em></strong>, que es opcional y puede implementarse a nivel de la interfaz.</p>
<h2 id="span-name5-reglas-de-herencia-en-interfacesspan-5-reglas-de-herencia-de-interfaces"><span name="5-reglas-de-herencia-en-interfaces"></span> <a href="#5-reglas-de-herencia-en-interfaces">5.</a> Reglas de Herencia de Interfaces</h2>
<p>Para lograr la herencia m&#xFA;ltiple a trav&#xE9;s de interfaces, debemos recordar algunas reglas. Veamos estas en detalle.</p>
<h3 id="span-name5-1-interfaz-que-extiende-otra-interfazspan-51-interfaz-que-extiende-otra-interfaz"><span name="5-1-interfaz-que-extiende-otra-interfaz"></span> <a href="#5-1-interfaz-que-extiende-otra-interfaz">5.1</a> Interfaz que Extiende Otra Interfaz</h3>
<p>Cuando una interfaz extiende (<em>extends</em>) otra interfaz, hereda todos los m&#xE9;todos abstractos de esa interfaz. Comencemos creando dos interfaces, <code>TieneColor</code> y <code>Forma</code>:</p>
<pre><code class="language-java">public interface TieneColor {
    String obtenerColor();
}

public interface Caja extends TieneColor {
    int obtenerAltura();
}
</code></pre>
<p>En el ejemplo anterior, <code>Caja</code> hereda de <code>TieneColor</code> utilizando la palabra clave <code>extends</code>. Al hacerlo, la interfaz <code>Caja</code> hereda <code>obtenerColor</code>. Como resultado, la interfaz <code>Caja</code> ahora tiene dos m&#xE9;todos: <code>obtenerColor</code> y <code>obtenerAltura</code>.</p>
<h3 id="span-name5-2-clase-abstracta-que-implementa-una-interfazspan-52-clase-abstracta-que-implementa-una-interfaz"><span name="5-2-clase-abstracta-que-implementa-una-interfaz"></span> <a href="#5-2-clase-abstracta-que-implementa-una-interfaz">5.2</a> Clase Abstracta que Implementa una Interfaz</h3>
<p>Cuando una clase abstracta implementa una interfaz, hereda todos sus m&#xE9;todos <em>abstract</em> y <em>default</em>. Consideremos la interfaz <code>Transformar</code> y la clase abstracta <code>Veh&#xED;culo</code> que la implementa:</p>
<pre><code class="language-java">public interface Transformar {
    
    void transformar();

    default void imprimirEspecificaciones(){
        System.out.println(&quot;Especificaciones de Transformaci&#xF3;n&quot;);
    }
}

public abstract class Veh&#xED;culo implements Transformar {}
</code></pre>
<p>En este ejemplo, la clase <code>Veh&#xED;culo</code> hereda dos m&#xE9;todos: el m&#xE9;todo abstracto <code>transformar</code> y el m&#xE9;todo <em>default</em> <code>imprimirEspecificaciones</code>.</p>
<h2 id="span-name6-interfaces-funcionalesspan-6-interfaces-funcionales"><span name="6-interfaces-funcionales"></span> <a href="#6-interfaces-funcionales">6.</a> Interfaces Funcionales</h2>
<p>Java ha tenido muchas interfaces funcionales desde sus primeros d&#xED;as, como <code>Comparable</code> (desde Java 1.2) y <code>Runnable</code> (desde Java 1.0).</p>
<p>Java 8 introdujo nuevas interfaces funcionales como <code>Predicate</code>, <code>Consumer</code> y <code>Function</code>. Para obtener m&#xE1;s informaci&#xF3;n sobre estas, visita nuestro tutorial sobre Interfaces Funcionales en Java 8 en futuras lecciones.</p>
<h2 id="span-name7-conclusionspan-7-conclusi%C3%B3n"><span name="7-conclusion"></span> <a href="#7-conclusion">7.</a> Conclusi&#xF3;n</h2>
<p>En este tutorial, ofrecimos una visi&#xF3;n general de las interfaces en Java y hablamos sobre c&#xF3;mo usarlas para lograr polimorfismo y la herencia m&#xFA;ltiple.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Métodos static y default en Interfaces en Java]]></title><description><![CDATA[Los métodos static y default en interfaces merecen un análisis más profundo por sí mismos.

En este tutorial, aprenderemos cómo utilizar los métodos static y default en interfaces y discutiremos algunas situaciones en las que pueden ser útiles.]]></description><link>https://javamagician.com/java-metodos-static-default/</link><guid isPermaLink="false">6525588be9daa8aba6216a3b</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Tue, 10 Oct 2023 15:11:08 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-metodos-static-default_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-metodos-static-default_600x750.png" alt="M&#xE9;todos static y default en Interfaces en Java"><p>Java 8 introdujo algunas caracter&#xED;sticas completamente nuevas, incluyendo expresiones lambda, interfaces funcionales, referencias de m&#xE9;todos, flujos, Optional y m&#xE9;todos <em>static</em> y <em>default</em> en interfaces.</p>
<p>Algunas de estas caracter&#xED;sticas las cubriremos en otros art&#xED;culos. No obstante, los m&#xE9;todos <em>static</em> y <em>default</em> en interfaces merecen un an&#xE1;lisis m&#xE1;s profundo por s&#xED; mismos.</p>
<p>En este tutorial, aprenderemos <strong>c&#xF3;mo utilizar los m&#xE9;todos <em>static</em> y <em>default</em> en interfaces</strong> y discutiremos algunas situaciones en las que pueden ser &#xFA;tiles.</p>
<h2 id="span-name2-por-que-las-interfaces-necesitan-metodos-defaultspan-2-por-qu%C3%A9-las-interfaces-necesitan-m%C3%A9todos-default"><span name="2-por-que-las-interfaces-necesitan-metodos-default"></span> <a href="#2-por-que-las-interfaces-necesitan-metodos-default">2.</a> Por Qu&#xE9; las Interfaces Necesitan M&#xE9;todos <em>default</em></h2>
<p>Al igual que los m&#xE9;todos regulares de las interfaces, <strong>los m&#xE9;todos <em>default</em> son impl&#xED;citamente p&#xFA;blicos</strong>; no es necesario especificar el modificador <em>public</em>.</p>
<p>A diferencia de los m&#xE9;todos regulares de las interfaces, los <strong>declaramos con la palabra clave <em>default</em> al principio de la firma del m&#xE9;todo y proporcionan una implementaci&#xF3;n.</strong></p>
<p>Veamos un ejemplo sencillo:</p>
<pre><code class="language-java">public interface MiInterfaz {
    
    // m&#xE9;todos regulares de la interfaz
    
    default void metodoPredeterminado() {
        // implementaci&#xF3;n del m&#xE9;todo default
    }
}
</code></pre>
<p>La raz&#xF3;n por la cual la versi&#xF3;n Java 8 incluy&#xF3; m&#xE9;todos <em>default</em> es bastante obvia.</p>
<p>En un dise&#xF1;o t&#xED;pico basado en abstracciones, donde una interfaz tiene una o m&#xFA;ltiples implementaciones, si se agregan uno o m&#xE1;s m&#xE9;todos a la interfaz, todas las implementaciones tambi&#xE9;n se ver&#xE1;n obligadas a implementarlos. De lo contrario, el dise&#xF1;o simplemente se romper&#xE1;.</p>
<p>Los m&#xE9;todos <em>default</em> de las interfaces son una forma eficiente de abordar este problema. <strong>Nos permiten agregar nuevos m&#xE9;todos a una interfaz que est&#xE1;n autom&#xE1;ticamente disponibles en las implementaciones</strong>. Por lo tanto, no necesitamos modificar las clases que las implementan.</p>
<p>De esta manera, <strong>se conserva la compatibilidad hacia atr&#xE1;s</strong> sin tener que refactorizar los implementadores.</p>
<h2 id="span-name3-metodos-default-de-la-interfaz-en-accionspan-3-m%C3%A9todos-default-de-la-interfaz-en-acci%C3%B3n"><span name="3-metodos-default-de-la-interfaz-en-accion"></span> <a href="#3-metodos-default-de-la-interfaz-en-accion">3.</a> M&#xE9;todos <em>default</em> de la Interfaz en Acci&#xF3;n</h2>
<p>Para comprender mejor la funcionalidad de los m&#xE9;todos <em>default</em> de la interfaz, creemos un ejemplo sencillo.</p>
<p>Supongamos que tenemos una interfaz <code>Veh&#xED;culo</code> ingenua y solo una implementaci&#xF3;n. Podr&#xED;a haber m&#xE1;s, pero manteng&#xE1;moslo simple:</p>
<pre><code class="language-java">public interface Vehiculo {
    
    String obtenerMarca();
    
    String acelerar();
    
    String desacelerar();
    
    default String activarAlarma() {
        return &quot;Activando la alarma del veh&#xED;culo.&quot;;
    }
    
    default String desactivarAlarma() {
        return &quot;Desactivando la alarma del veh&#xED;culo.&quot;;
    }
}
</code></pre>
<p>Ahora escribamos la clase que implementa:</p>
<pre><code class="language-java">public class Coche implements Vehiculo {

    private String marca;
    
    // constructores/getters
    
    @Override
    public String obtenerMarca() {
        return marca;
    }
    
    @Override
    public String acelerar() {
        return &quot;El coche est&#xE1; acelerando.&quot;;
    }
    
    @Override
    public String desacelerar() {
        return &quot;El coche est&#xE1; desacelerando.&quot;;
    }
}
</code></pre>
<p>Finalmente, definamos una clase <code>main</code> t&#xED;pica, que crea una instancia de <code>Coche</code> y llama a sus m&#xE9;todos:</p>
<pre><code class="language-java">public static void main(String[] args) { 
    Vehiculo coche = new Coche(&quot;Aston Martin&quot;);
    System.out.println(coche.obtenerMarca());
    System.out.println(coche.acelerar());
    System.out.println(coche.desacelerar());
    System.out.println(coche.activarAlarma());
    System.out.println(coche.desactivarAlarma());
}
</code></pre>
<p>Por favor, ten en cuenta c&#xF3;mo los m&#xE9;todos <em>default</em>, <code>activarAlarma()</code> y <code>desactivarAlarma()</code>, de nuestra interfaz <code>Vehiculo</code> est&#xE1;n <strong>autom&#xE1;ticamente disponibles en la clase <code>Coche</code></strong>.</p>
<p>Adem&#xE1;s, si en alg&#xFA;n momento decidimos agregar m&#xE1;s m&#xE9;todos <em>default</em> a la interfaz Vehiculo, la aplicaci&#xF3;n seguir&#xE1; funcionando y no tendremos que obligar a la clase a proporcionar implementaciones para los nuevos m&#xE9;todos.</p>
<p>El uso m&#xE1;s com&#xFA;n de los m&#xE9;todos <em>default</em> de la interfaz es <strong>proporcionar incrementalmente funcionalidad adicional a un tipo dado sin descomponer las clases que la implementan.</strong></p>
<p>Adem&#xE1;s, podemos usarlos para <strong>proporcionar funcionalidad adicional en torno a un m&#xE9;todo abstracto existente</strong>:</p>
<pre><code class="language-java">public interface Vehiculo {
    
    // m&#xE9;todos adicionales de la interfaz 
    
    double obtenerVelocidad();
    
    default double obtenerVelocidadEnKMH(double velocidad) {
       // conversi&#xF3;n      
    }
}
</code></pre>
<h2 id="span-name4-reglas-de-herencia-de-multiples-interfacesspan-4-reglas-de-herencia-de-m%C3%BAltiples-interfaces"><span name="4-reglas-de-herencia-de-multiples-interfaces"></span> <a href="#4-reglas-de-herencia-de-multiples-interfaces">4.</a> Reglas de Herencia de M&#xFA;ltiples Interfaces</h2>
<p>Los m&#xE9;todos <em>default</em> de la interfaz son una caracter&#xED;stica bastante buena, pero hay algunas advertencias que vale la pena mencionar. Dado que Java permite que las clases implementen m&#xFA;ltiples interfaces, es importante saber <strong>qu&#xE9; sucede cuando una clase implementa varias interfaces que definen los mismos m&#xE9;todos <em>default</em></strong>.</p>
<p>Para comprender mejor este escenario, definamos una nueva interfaz <code>Alarma</code> y refactoricemos la clase <code>Coche</code>:</p>
<pre><code class="language-java">public interface Alarma {

    default String activarAlarma() {
        return &quot;Activando la alarma.&quot;;
    }
    
    default String desactivarAlarma() {
        return &quot;Desactivando la alarma.&quot;;
    }
}
</code></pre>
<p>Con esta nueva interfaz que define su propio conjunto de m&#xE9;todos <em>default</em>, la clase <code>Coche</code> implementar&#xED;a tanto <code>Vehiculo</code> como <code>Alarma</code>:</p>
<pre><code class="language-java">public class Coche implements Vehiculo, Alarma {
    // ...
}
</code></pre>
<p>En este caso, <strong>el c&#xF3;digo simplemente no se compilar&#xE1;, ya que hay un conflicto causado por la herencia de m&#xFA;ltiples interfaces</strong> (tambi&#xE9;n conocido como el <a href="https://es.wikipedia.org/wiki/Herencia_m%C3%BAltiple?ref=javamagician.com">Problema del Diamante</a>). La clase <code>Coche</code> heredar&#xED;a ambos conjuntos de m&#xE9;todos <em>default</em>. Entonces, &#xBF;cu&#xE1;les deber&#xED;amos llamar?</p>
<p><strong>Para resolver esta ambig&#xFC;edad, debemos proporcionar expl&#xED;citamente una implementaci&#xF3;n para los m&#xE9;todos</strong>:</p>
<pre><code class="language-java">@Override
public String activarAlarma() {
    // implementaci&#xF3;n personalizada
}
    
@Override
public String desactivarAlarma() {
    // implementaci&#xF3;n personalizada
}
</code></pre>
<p>Tambi&#xE9;n podemos <strong>hacer que nuestra clase utilice los m&#xE9;todos <em>default</em> de una de las interfaces</strong>.</p>
<p>Veamos un ejemplo que utiliza los m&#xE9;todos <em>default</em> de la interfaz <code>Vehiculo</code>:</p>
<pre><code class="language-java">@Override
public String activarAlarma() {
    return Vehiculo.super.activarAlarma();
}

@Override
public String desactivarAlarma() {
    return Vehiculo.super.desactivarAlarma();
}
</code></pre>
<p>De manera similar, podemos hacer que la clase utilice los m&#xE9;todos <em>default</em> definidos dentro de la interfaz <code>Alarma</code>:</p>
<pre><code class="language-java">@Override
public String activarAlarma() {
    return Alarma.super.activarAlarma();
}

@Override
public String desactivarAlarma() {
    return Alarma.super.desactivarAlarma();
}
</code></pre>
<p>Incluso es <strong>posible hacer que la clase <code>Coche</code> utilice ambos conjuntos de m&#xE9;todos <em>default</em></strong>:</p>
<pre><code class="language-java">@Override
public String activarAlarma() {
    return Vehiculo.super.activarAlarma() + &quot; &quot; + Alarma.super.activarAlarma();
}
    
@Override
public String desactivarAlarma() {
    return Vehiculo.super.desactivarAlarma() + &quot; &quot; + Alarma.super.desactivarAlarma();
}
</code></pre>
<h2 id="span-name5-metodos-static-de-la-interfazspan-5-m%C3%A9todos-static-de-la-interfaz"><span name="5-metodos-static-de-la-interfaz"></span> <a href="#5-metodos-static-de-la-interfaz">5.</a> M&#xE9;todos <em>static</em> de la Interfaz</h2>
<p>Adem&#xE1;s de declarar m&#xE9;todos <em>default</em> en las interfaces, <strong>Java 8 tambi&#xE9;n nos permite definir e implementar m&#xE9;todos <em>static</em> en las interfaces.</strong></p>
<p>Dado que los m&#xE9;todos <em>static</em> no pertenecen a un objeto en particular, no forman parte de la API de las clases que implementan la interfaz; por lo tanto, deben ser <strong>llamados usando el nombre de la interfaz precediendo el nombre del m&#xE9;todo</strong>.</p>
<p>Para comprender c&#xF3;mo funcionan los m&#xE9;todos <em>static</em> en las interfaces, refactoricemos la interfaz <code>Vehiculo</code> y agreguemos un m&#xE9;todo de utilidad <em>static</em> a ella:</p>
<pre><code class="language-java">public interface Vehiculo {
    
    // m&#xE9;todos regulares / predeterminados de la interfaz
    
    static int obtenerPotencia(int rpm, int torque) {
        return (rpm * torque) / 1337;
    }
}
</code></pre>
<p><strong>Definir un m&#xE9;todo <em>static</em> dentro de una interfaz es id&#xE9;ntico a definirlo en una clase</strong>. Adem&#xE1;s, un m&#xE9;todo <em>static</em> puede ser invocado dentro de otros m&#xE9;todos <em>static</em> y <em>default</em>.</p>
<p>Supongamos que queremos calcular la potencia de un motor de un veh&#xED;culo dado. Solo llamamos al m&#xE9;todo obtenerPotencia():</p>
<pre><code class="language-java">Vehiculo.obtenerPotencia(1000, 400));
</code></pre>
<p>La idea detr&#xE1;s de los m&#xE9;todos <em>static</em> de la interfaz es proporcionar un mecanismo simple que nos permita <strong>aumentar el grado de <a href="https://es.wikipedia.org/wiki/Cohesi%C3%B3n_(inform%C3%A1tica)?ref=javamagician.com">cohesi&#xF3;n</a></strong> de un dise&#xF1;o reuniendo m&#xE9;todos relacionados en un solo lugar sin tener que crear un objeto.</p>
<p><strong>Lo mismo se puede hacer con clases abstractas</strong>. La principal diferencia es que <strong>las clases abstractas pueden tener constructores, estado y comportamiento</strong>.</p>
<p>Adem&#xE1;s, los m&#xE9;todos <em>static</em> en las interfaces permiten agrupar m&#xE9;todos de utilidad relacionados sin tener que crear clases de utilidad artificiales que sean simplemente marcadores de posici&#xF3;n para m&#xE9;todos <em>static</em>.</p>
<h2 id="span-name6-conclusionspan-6-conclusi%C3%B3n"><span name="6-conclusion"></span> <a href="#6-conclusion">6.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, exploramos a fondo el uso de m&#xE9;todos <em>static</em> y <em>default</em> de la interfaz en Java 8. A primera vista, esta caracter&#xED;stica puede parecer un poco desordenada, especialmente desde la perspectiva de un purista orientado a objetos. Idealmente, las interfaces no deber&#xED;an encapsular comportamiento, y solo deber&#xED;amos usarlas para definir la API p&#xFA;blica de un cierto tipo.</p>
<p>Sin embargo, cuando se trata de mantener la compatibilidad hacia atr&#xE1;s con c&#xF3;digo existente, los m&#xE9;todos <em>static</em> y <em>default</em> son un buen compromiso.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[La Palabra Clave static en Java]]></title><description><![CDATA[En este tutorial, exploraremos en detalle el modificador static del lenguaje Java.

Descubriremos cómo podemos aplicar la palabra clave static a variables, métodos, bloques y clases anidadas, y qué diferencia marca.]]></description><link>https://javamagician.com/java-palabra-clave-static/</link><guid isPermaLink="false">651fd964e9daa8aba621691b</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Fri, 06 Oct 2023 12:17:17 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-palabra-clave-static_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-palabra-clave-static_600x750.png" alt="La Palabra Clave static en Java"><p>En este tutorial, exploraremos en detalle el modificador <em>static</em> del lenguaje Java.</p>
<p>Descubriremos c&#xF3;mo podemos aplicar la palabra clave <em>static</em> a variables, m&#xE9;todos, bloques y clases anidadas, y qu&#xE9; diferencia marca.</p>
<h2 id="span-name2-la-anatomia-de-la-palabra-clave-staticspan-2-la-anatom%C3%ADa-de-la-palabra-clave-static"><span name="2-la-anatomia-de-la-palabra-clave-static"></span> <a href="#2-la-anatomia-de-la-palabra-clave-static">2.</a> La Anatom&#xED;a de la Palabra Clave <em>static</em></h2>
<p>En el lenguaje de programaci&#xF3;n Java, <strong>la palabra clave <em>static</em> significa que el miembro en particular pertenece a un tipo en s&#xED; mismo, en lugar de pertenecer a una instancia de ese tipo.</strong></p>
<p>Esto significa que crearemos solo una instancia de ese miembro est&#xE1;tico que se comparte entre todas las instancias de la clase.</p>
<p><img src="https://javamagician.com/content/images/2023/10/static_word.png" alt="La Palabra Clave static en Java" loading="lazy"></p>
<p>Podemos aplicar la palabra clave a variables, m&#xE9;todos, bloques y clases anidadas.</p>
<h2 id="span-name3-los-campos-static-o-variables-de-clasespan-3-los-campos-static-o-variables-de-clase"><span name="3-los-campos-static-o-variables-de-clase"></span> <a href="#3-los-campos-static-o-variables-de-clase">3.</a> Los Campos <em>static</em> (o Variables de Clase)</h2>
<p>En Java, <strong>cuando declaramos un campo como <em>static</em>, se crea exactamente una copia de ese campo y se comparte entre todas las instancias de esa clase.</strong></p>
<p>No importa cu&#xE1;ntas veces instanciemos una clase. Siempre habr&#xE1; una sola copia del campo <em>static</em> perteneciente a ella. El valor de este campo <em>static</em> se comparte entre todos los objetos de la misma clase.</p>
<p>Desde la perspectiva de la memoria, <strong>las variables est&#xE1;ticas se almacenan en la memoria heap.</strong></p>
<h3 id="span-name3-1-ejemplo-del-campo-staticspan-31-ejemplo-del-campo-static"><span name="3-1-ejemplo-del-campo-static"></span> <a href="#3-1-ejemplo-del-campo-static">3.1.</a> Ejemplo del Campo <em>static</em></h3>
<p>Supongamos que tenemos una clase <code>Coche</code> con varios atributos (variables de instancia).</p>
<p>Cada vez que creamos nuevos objetos a partir de esta plantilla <code>Coche</code>, cada nuevo objeto tendr&#xE1; su copia distintiva de estas variables de instancia.</p>
<p>Sin embargo, supongamos que queremos una variable que mantenga el conteo del n&#xFA;mero de objetos <code>Coche</code> instanciados y se comparta entre todas las instancias para que puedan acceder a ella e incrementarla al inicializarse.</p>
<p>Ah&#xED; es donde entran en juego las variables <em>static</em>:</p>
<pre><code class="language-java">public class Coche {
    private String nombre;
    private String motor;
    
    public static int cantidadDeCoches;
    
    public Coche(String nombre, String motor) {
        this.nombre = nombre;
        this.motor = motor;
        cantidadDeCoches++;
    }

    // getters y setters
}
</code></pre>
<p>Ahora, por cada objeto de esta clase que instanciemos, la misma copia de la variable <code>cantidadDeCoches</code> se incrementar&#xE1;.</p>
<p>Entonces, para este caso, esto ser&#xE1; cierto:</p>
<pre><code class="language-java">@Test
public void cuandoSeInicializanObjetosDeCoche_LaCuentaEstaticaAumenta() {
    new Coche(&quot;Seat&quot;, &quot;Panda&quot;);
    new Coche(&quot;Porsche&quot;, &quot;Taycan&quot;);
 
    assertEquals(2, Coche.cantidadDeCoches);
}
</code></pre>
<h3 id="span-name3-2-razones-para-usar-campos-staticspan-32-razones-para-usar-campos-static"><span name="3-2-razones-para-usar-campos-static"></span> <a href="#3-2-razones-para-usar-campos-static">3.2.</a> Razones para Usar Campos <em>static</em></h3>
<p>Aqu&#xED; hay algunas razones por las cuales querr&#xED;amos usar campos <em>static</em>:</p>
<ul>
<li>Cuando el valor de la variable es independiente de los objetos.</li>
<li>Cuando se supone que el valor debe ser compartido entre todos los objetos.</li>
</ul>
<h3 id="span-name3-3-puntos-clave-a-recordarspan-33-puntos-clave-a-recordar"><span name="3-3-puntos-clave-a-recordar"></span> <a href="#3-3-puntos-clave-a-recordar">3.3.</a> Puntos Clave a Recordar</h3>
<p>Dado que las variables <em>static</em> pertenecen a una clase, podemos acceder a ellas directamente utilizando el nombre de la clase. Por lo tanto, <strong>no necesitamos ninguna referencia a un objeto.</strong></p>
<p>Solo podemos declarar variables <em>static</em> a nivel de clase.</p>
<p><strong>Podemos acceder a campos <em>static</em> sin inicializar un objeto.</strong></p>
<p>Finalmente, podemos acceder a campos <em>static</em> utilizando una referencia a un objeto (como <code>ford.cantidadDeCoches++</code>). Pero debemos evitar esto porque se vuelve dif&#xED;cil determinar si es una variable de instancia o una variable de clase. En su lugar, <strong>siempre debemos referirnos a las variables <em>static</em> utilizando el nombre de la clase</strong> (<code>Coche.cantidadDeCoches++</code>).</p>
<h2 id="span-name4-los-metodos-static-o-metodos-de-clasespan-4-los-m%C3%A9todos-static-o-m%C3%A9todos-de-clase"><span name="4-los-metodos-static-o-metodos-de-clase"></span> <a href="#4-los-metodos-static-o-metodos-de-clase">4.</a> Los M&#xE9;todos <em>static</em> (o M&#xE9;todos de Clase)</h2>
<p>Al igual que con los campos <em>static</em>, los m&#xE9;todos <em>static</em> tambi&#xE9;n pertenecen a una clase en lugar de a un objeto. Por lo tanto, podemos llamarlos sin crear un objeto de la clase en la que residen.</p>
<h3 id="span-name4-1-ejemplo-del-metodo-staticspan-41-ejemplo-del-m%C3%A9todo-static"><span name="4-1-ejemplo-del-metodo-static"></span> <a href="#4-1-ejemplo-del-metodo-static">4.1.</a> Ejemplo del M&#xE9;todo <em>static</em></h3>
<p>Generalmente, usamos m&#xE9;todos <em>static</em> para realizar una operaci&#xF3;n que no depende de la creaci&#xF3;n de una instancia.</p>
<p>Para compartir c&#xF3;digo entre todas las instancias de esa clase, lo escribimos en un m&#xE9;todo <em>static</em>:</p>
<pre><code class="language-java">static void establecerCantidadDeCoches(int cantidadDeCoches) {
    Coche.cantidadDeCoches = cantidadDeCoches;
}
</code></pre>
<p>Tambi&#xE9;n com&#xFA;nmente usamos m&#xE9;todos <em>static</em> para crear clases de utilidad o ayudantes para que podamos obtenerlos sin crear un nuevo objeto de esas clases.</p>
<p>Como ejemplos, podemos observar las clases de utilidad de <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collections.html?ref=javamagician.com">Collections</a> o <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Math.html?ref=javamagician.com">Math</a> en JDK, <a href="https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html?ref=javamagician.com">StringUtils</a> de Apache o <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/CollectionUtils.html?ref=javamagician.com">CollectionUtils</a> del framework Spring y notar que todos sus m&#xE9;todos de utilidad son <em>static</em>.</p>
<h3 id="span-name4-2-razones-para-usar-metodos-staticspan-42-razones-para-usar-m%C3%A9todos-static"><span name="4-2-razones-para-usar-metodos-static"></span> <a href="#4-2-razones-para-usar-metodos-static">4.2.</a> Razones para Usar M&#xE9;todos <em>static</em></h3>
<p>Echemos un vistazo a algunas razones por las que querr&#xED;amos usar m&#xE9;todos <em>static</em>:</p>
<ul>
<li>Para acceder/manipular variables est&#xE1;ticas y otros m&#xE9;todos est&#xE1;ticos que no dependen de objetos.</li>
<li>Los m&#xE9;todos <em>static</em> se usan ampliamente en clases de utilidad y ayudantes.</li>
</ul>
<h3 id="span-name4-3-puntos-clave-a-recordarspan-43-puntos-clave-a-recordar"><span name="4-3-puntos-clave-a-recordar"></span> <a href="#4-3-puntos-clave-a-recordar">4.3.</a> Puntos Clave a Recordar</h3>
<p>Los m&#xE9;todos <em>static</em> en Java se resuelven en tiempo de compilaci&#xF3;n. Dado que la sobrescritura de m&#xE9;todos es parte del <a href="https://javamagician.com/java-polimorfismo/#3-polimorfismo-dinamico">polimorfismo en tiempo de ejecuci&#xF3;n</a>, <strong>los m&#xE9;todos <em>static</em> no pueden ser sobrescritos</strong>.</p>
<p><strong>Los m&#xE9;todos abstractos no pueden ser <em>static</em>.</strong></p>
<p><strong>Los m&#xE9;todos <em>static</em> no pueden usar las palabras clave <em>this</em> o <em>super</em>.</strong></p>
<p>Las siguientes combinaciones de m&#xE9;todos y variables de instancia y de clase son v&#xE1;lidas:</p>
<ul>
<li>Los m&#xE9;todos de instancia pueden acceder directamente tanto a los m&#xE9;todos de instancia como a las variables de instancia.</li>
<li>Los m&#xE9;todos de instancia tambi&#xE9;n pueden acceder directamente a variables y m&#xE9;todos <em>static</em>.</li>
<li>Los m&#xE9;todos <em>static</em> pueden acceder a todas las variables <em>static</em> y a otros m&#xE9;todos <em>static</em>.</li>
<li><strong>Los m&#xE9;todos <em>static</em> no pueden acceder directamente a variables de instancia y m&#xE9;todos de instancia.</strong> Necesitan alguna referencia de objeto para hacerlo.</li>
</ul>
<h3 id="span-name4-4-llamar-a-un-metodo-no-static-en-un-metodo-static-en-javaspan-44-llamar-a-un-m%C3%A9todo-no-static-en-un-m%C3%A9todo-static-en-java"><span name="4-4-llamar-a-un-metodo-no-static-en-un-metodo-static-en-java"></span> <a href="#4-4-llamar-a-un-metodo-no-static-en-un-metodo-static-en-java">4.4.</a> Llamar a un M&#xE9;todo No <em>static</em> en un M&#xE9;todo <em>static</em> en Java</h3>
<p>Para llamar a un m&#xE9;todo no est&#xE1;tico en un m&#xE9;todo <em>static</em>, debemos usar una instancia de la clase que contiene el m&#xE9;todo no est&#xE1;tico. <strong>Este es un caso de uso com&#xFA;n al llamar a un m&#xE9;todo no est&#xE1;tico en el m&#xE9;todo <em>static</em> <code>main()</code>, por ejemplo.</strong></p>
<p>Consideremos un ejemplo de la clase <code>Coche</code> que presentamos anteriormente en este art&#xED;culo y que define los siguientes m&#xE9;todos:</p>
<pre><code class="language-java">public String getNombre() {
    return nombre;
}

public String getMotor() {
    return motor;
}

public static String getInformacionDeCoches(Coche coche) {
    return coche.getNombre() + &quot;-&quot; + coche.getMotor();
}
</code></pre>
<p>Como podemos ver, estamos llamando a los m&#xE9;todos <code>getNombre()</code> y <code>getMotor()</code>, que son m&#xE9;todos no est&#xE1;ticos, en el m&#xE9;todo <em>static</em> <code>getInformacionDeCoches()</code>. Esto solo es posible porque usamos una instancia del objeto <code>Coche</code> para acceder a estos m&#xE9;todos. De lo contrario, obtendr&#xED;amos este mensaje de error: &quot;Non-static method &#x2018;getNombre()&#x2019; cannot be referenced from a static context&quot; (&quot;M&#xE9;todo no est&#xE1;tico &apos;getNombre()&apos; no puede ser referenciado desde un contexto est&#xE1;tico&quot;).</p>
<h2 id="span-name5-bloques-staticspan-5-bloques-static"><span name="5-bloques-static"></span> <a href="#5-bloques-static">5.</a> Bloques <em>static</em></h2>
<p>Usamos un bloque <em>static</em> para inicializar variables <em>static</em>. Aunque podemos inicializar variables <em>static</em> directamente durante la declaraci&#xF3;n, hay situaciones en las que necesitamos realizar un procesamiento multilineal. En tales casos, los bloques <em>static</em> son &#xFA;tiles.</p>
<h3 id="span-name5-1-el-ejemplo-del-bloque-staticspan-51-el-ejemplo-del-bloque-static"><span name="5-1-el-ejemplo-del-bloque-static"></span> <a href="#5-1-el-ejemplo-del-bloque-static">5.1.</a> El Ejemplo del Bloque <em>static</em></h3>
<p>Por ejemplo, supongamos que queremos inicializar un objeto <code>List</code> con algunos valores predefinidos.</p>
<p>Esto se vuelve f&#xE1;cil con bloques <em>static</em>:</p>
<pre><code class="language-java">public class DemoBloqueEstatico {
    public static List&lt;String&gt; rangos = new LinkedList&lt;&gt;();

    static {
        rangos.add(&quot;Oro&quot;);
        rangos.add(&quot;Platino&quot;);
        rangos.add(&quot;Diamante&quot;);
    }
    
    static {
        rangos.add(&quot;Master&quot;);
        rangos.add(&quot;Grand Master&quot;);
    }
}
</code></pre>
<p>No ser&#xED;a posible inicializar un objeto <code>List</code> con todos los valores iniciales junto con la declaraci&#xF3;n. Por eso hemos utilizado el bloque <em>static</em> aqu&#xED;.</p>
<h3 id="span-name5-2-razones-para-usar-bloques-staticspan-52-razones-para-usar-bloques-static"><span name="5-2-razones-para-usar-bloques-static"></span> <a href="#5-2-razones-para-usar-bloques-static">5.2.</a> Razones para Usar Bloques <em>static</em></h3>
<p>A continuaci&#xF3;n, algunas razones para usar bloques <em>static</em>:</p>
<ul>
<li>Si la inicializaci&#xF3;n de variables <em>static</em> requiere alguna l&#xF3;gica adicional aparte de la asignaci&#xF3;n.</li>
<li>Si la inicializaci&#xF3;n de variables <em>static</em> propensas a errores y necesita manejo de excepciones.</li>
</ul>
<h3 id="span-name5-3-puntos-clave-a-recordarspan-53-puntos-clave-a-recordar"><span name="5-3-puntos-clave-a-recordar"></span> <a href="#5-3-puntos-clave-a-recordar">5.3.</a> Puntos Clave a Recordar</h3>
<p><strong>Una clase puede tener varios bloques <em>static</em>.</strong></p>
<p>Los campos <em>static</em> y los bloques <em>static</em> se resuelven y ejecutan en el mismo orden en que est&#xE1;n presentes en la clase.</p>
<h2 id="span-name6-una-clase-staticspan-6-una-clase-static"><span name="6-una-clase-static"></span> <a href="#6-una-clase-static">6.</a> Una Clase <em>static</em></h2>
<p>Java nos permite crear una clase dentro de otra clase. Proporciona una forma de agrupar elementos que solo utilizaremos en un solo lugar. Esto ayuda a mantener nuestro c&#xF3;digo m&#xE1;s organizado y legible.</p>
<p>En general, la arquitectura de clases anidadas se divide en dos tipos:</p>
<ul>
<li>Las clases anidadas que declaramos como <em>static</em> se llaman <strong>clases anidadas <em>static</em></strong>.</li>
<li>Las clases anidadas que no son <em>static</em> se llaman <strong>clases internas</strong>.</li>
</ul>
<p>La diferencia principal entre estas dos es que las clases internas tienen acceso a todos los miembros de la clase contenedora (incluidos los <em>private</em>), mientras que las clases anidadas <em>static</em> solo tienen acceso a miembros <em>static</em> de la clase externa.</p>
<p>De hecho, <strong>las clases anidadas <em>static</em> se comportan exactamente como cualquier otra clase de nivel superior, pero est&#xE1;n contenidas en la &#xFA;nica clase que las acceder&#xE1;, para proporcionar una mejor comodidad en el empaquetado.</strong></p>
<h3 id="span-name6-1-ejemplo-de-clase-staticspan-61-ejemplo-de-clase-static"><span name="6-1-ejemplo-de-clase-static"></span> <a href="#6-1-ejemplo-de-clase-static">6.1.</a> Ejemplo de Clase <em>static</em></h3>
<p>El enfoque m&#xE1;s ampliamente utilizado para crear objetos singleton es a trav&#xE9;s de una clase anidada <em>static</em>:</p>
<pre><code class="language-java">public class Singleton  {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instancia = new Singleton();
    }

    public static Singleton obtenerInstancia() {
        return SingletonHolder.instancia;
    }
}
</code></pre>
<p>Usamos este m&#xE9;todo porque no requiere sincronizaci&#xF3;n y es f&#xE1;cil de aprender e implementar.</p>
<p>Otro ejemplo de clase anidada <em>static</em>, donde se muestra la visibilidad entre los miembros de la clase principal y anidada, y viceversa:</p>
<pre><code class="language-java">public class Pizza {

    private static String cantidadCocinada;
    private boolean esMasaDelgada;

    public static class ContadorVentasDePizza {

        private static String cantidadOrdenada;
        public static String cantidadEntregada;

        ContadorVentasDePizza() {
            System.out.println(&quot;Campo est&#xE1;tico de la clase contenedora es &quot;
              + Pizza.cantidadCocinada);
            System.out.println(&quot;Campo no est&#xE1;tico de la clase contenedora es &quot;
              + new Pizza().esMasaDelgada);
        }
    }

    Pizza() {
        System.out.println(&quot;Campo no est&#xE1;tico p&#xFA;blico de la clase est&#xE1;tica es &quot;
          + ContadorVentasDePizza.cantidadEntregada);
        System.out.println(&quot;Campo no est&#xE1;tico privado de la clase est&#xE1;tica es &quot;
          + ContadorVentasDePizza.cantidadOrdenada);
    }

    public static void main(String[] a) {
        new Pizza.ContadorVentasDePizza();
    }
}
</code></pre>
<p>El resultado cuando ejecutamos el m&#xE9;todo principal es:</p>
<pre><code>Campo est&#xE1;tico de la clase contenedora es null
Campo no est&#xE1;tico de la clase contenedora es false
Campo no est&#xE1;tico p&#xFA;blico de la clase est&#xE1;tica es null
Campo no est&#xE1;tico privado de la clase est&#xE1;tica es null
</code></pre>
<h3 id="span-name6-2-razones-para-usar-una-clase-staticspan-62-razones-para-usar-una-clase-static"><span name="6-2-razones-para-usar-una-clase-static"></span> <a href="#6-2-razones-para-usar-una-clase-static">6.2.</a> Razones para Usar una Clase <em>static</em></h3>
<p>Veamos algunas razones para usar clases anidadas <em>static</em> en nuestro c&#xF3;digo:</p>
<ul>
<li>Agrupar clases que solo se usar&#xE1;n en un lugar aumenta la encapsulaci&#xF3;n.</li>
<li>Acercamos el c&#xF3;digo al &#xFA;nico lugar que lo utilizar&#xE1;. Esto aumenta la legibilidad y facilita el mantenimiento.</li>
<li>Si una clase anidada no requiere acceso a los miembros de instancia de su clase contenedora, es mejor declararla como <em>static</em>. De esta manera, no estar&#xE1; acoplada a la clase externa y, por lo tanto, ser&#xE1; m&#xE1;s &#xF3;ptima, ya que no requerir&#xE1; memoria heap o memoria stack.</li>
</ul>
<h3 id="span-name6-3-puntos-clave-a-recordarspan-63-puntos-clave-a-recordar"><span name="6-3-puntos-clave-a-recordar"></span> <a href="#6-3-puntos-clave-a-recordar">6.3.</a> Puntos Clave a Recordar</h3>
<p><strong>B&#xE1;sicamente, una clase anidada <em>static</em> no tiene acceso a ning&#xFA;n miembro de instancia de la clase contenedora</strong>. Solo puede acceder a trav&#xE9;s de una referencia de objeto.</p>
<p>Las clases anidadas <em>static</em> pueden acceder a todos los miembros est&#xE1;ticos de la clase contenedora, incluidos los privados.</p>
<p><strong>La especificaci&#xF3;n de programaci&#xF3;n de Java no nos permite declarar la clase de nivel superior como <em>static</em></strong>. Solo las clases dentro de las clases (clases anidadas) pueden ser declaradas como <em>static</em>.</p>
<h2 id="span-name7-comprendiendo-el-error-non-static-variable-cannot-be-referenced-from-a-static-contextspan-7-comprendiendo-el-error-non-static-variable-cannot-be-referenced-from-a-static-context"><span name="7-comprendiendo-el-error-non-static-variable-cannot-be-referenced-from-a-static-context"></span> <a href="#7-comprendiendo-el-error-non-static-variable-cannot-be-referenced-from-a-static-context">7.</a> Comprendiendo el Error &quot;Non-static variable cannot be referenced from a static context&quot;</h2>
<p>Por lo general, este error ocurre cuando usamos una variable no est&#xE1;tica dentro de un contexto est&#xE1;tico.</p>
<p>Como vimos anteriormente, las variables est&#xE1;ticas pertenecen a la clase y se cargan en el momento de la carga de la clase. Por otro lado, necesitamos crear un objeto para hacer referencia a las variables no est&#xE1;ticas.</p>
<p>Por lo tanto, <strong>el compilador de Java se queja porque se necesita un objeto para llamar o usar variables no est&#xE1;ticas.</strong></p>
<p>Ahora que sabemos qu&#xE9; causa el error, ilustr&#xE9;moslo con un ejemplo:</p>
<pre><code class="language-java">public class MiClase { 
    int variableDeInstancia = 0; 
    
    public static void metodoEstatico() { 
        System.out.println(variableDeInstancia); 
    } 
    
    public static void main(String[] args) {
        MiClase.metodoEstatico();
    }
} 
</code></pre>
<p>Como podemos ver, estamos usando <code>variableDeInstancia</code>, que es una variable no est&#xE1;tica, dentro del m&#xE9;todo est&#xE1;tico <code>metodoEstatico</code>.</p>
<p>Como resultado, obtendremos el error &quot;Non-static variable cannot be referenced from a static context&quot; (No se puede hacer referencia a una variable no est&#xE1;tica desde un contexto est&#xE1;tico).</p>
<h2 id="span-name8-conclusionspan-8-conclusi%C3%B3n"><span name="8-conclusion"></span> <a href="#8-conclusion">8.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, vimos en acci&#xF3;n la palabra clave <em>static</em>.</p>
<p>Tambi&#xE9;n discutimos las razones y ventajas de usar campos est&#xE1;ticos, m&#xE9;todos est&#xE1;ticos, bloques est&#xE1;ticos y clases anidadas est&#xE1;ticas.</p>
<p>Finalmente, aprendimos qu&#xE9; provoca que el compilador falle con el error &quot;No se puede hacer referencia a una variable no est&#xE1;tica desde un contexto est&#xE1;tico&quot;.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[La Palabra Clave final en Java]]></title><description><![CDATA[Si bien la herencia nos permite reutilizar código existente, a veces necesitamos establecer limitaciones a la extensibilidad por diversas razones; la palabra clave final nos permite hacer precisamente eso. En este articulo veremos como declarar una constante en Java.]]></description><link>https://javamagician.com/java-palabra-clave-final/</link><guid isPermaLink="false">651fac83e9daa8aba621684e</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Conceptos básicos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Fri, 06 Oct 2023 07:27:22 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-palabra-clave-final_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-palabra-clave-final_600x750.png" alt="La Palabra Clave final en Java"><p>Si bien la herencia nos permite reutilizar c&#xF3;digo existente, a veces necesitamos <strong>establecer limitaciones a la extensibilidad</strong> por diversas razones; la palabra clave <em>final</em> nos permite hacer precisamente eso.</p>
<p>En este tutorial, examinaremos lo que significa la palabra clave <em>final</em> para clases, m&#xE9;todos y variables.</p>
<h2 id="span-name2-clases-finalspan-2-clases-final"><span name="2-clases-final"></span> <a href="#2-clases-final">2.</a> Clases <em>final</em></h2>
<p><strong>Las clases marcadas como <em>final</em> no pueden ser extendidas</strong>. Si observamos el c&#xF3;digo de las bibliotecas centrales de Java, encontraremos muchas clases finales all&#xED;. Un ejemplo es la clase <em>String</em>.</p>
<p>Consideremos la situaci&#xF3;n si pudi&#xE9;ramos extender la clase <em>String</em>, sobrescribir cualquiera de sus m&#xE9;todos y sustituir todas las instancias de <em>String</em> con las instancias de nuestra subclase espec&#xED;fica de <em>String</em>.</p>
<p>El resultado de las operaciones sobre objetos <em>String</em> se volver&#xED;a entonces impredecible. Y dado que la clase <em>String</em> se utiliza en todas partes, eso ser&#xED;a inaceptable. Es por eso que la clase <em>String</em> est&#xE1; marcada como <em>final</em>.</p>
<p>Cualquier intento de heredar de una clase <em>final</em> provocar&#xE1; un error del compilador. Para demostrar esto, creemos la clase <em>final</em> <code>Gato</code>:</p>
<pre><code class="language-java">public final class Gato {
    private int peso;
    // getter y setter est&#xE1;ndar
}
</code></pre>
<p>Y tratemos de extenderla:</p>
<pre><code class="language-java">public class GatoNegro extends Gato {
}
</code></pre>
<p>Veremos el error del compilador:</p>
<pre><code class="language-plain">The type GatoNegro cannot subclass the final class Gato
</code></pre>
<p>Nota que <strong>la palabra clave <em>final</em> en una declaraci&#xF3;n de clase no significa que los objetos de esta clase sean inmutables</strong>. Podemos cambiar libremente los campos del objeto <code>Gato</code>:</p>
<pre><code class="language-java">Gato gato = new Gato();
gato.setPeso(1);

assertEquals(1, gato.getPeso());
</code></pre>
<p>Simplemente no podemos extenderla.</p>
<p>Si seguimos estrictamente las reglas de un buen dise&#xF1;o, debemos crear y documentar una clase con cuidado o declararla <em>final</em> por razones de seguridad. Sin embargo, debemos tener cuidado al crear clases finales.</p>
<p>Observa que hacer que una clase sea <em>final</em> significa que ning&#xFA;n otro programador puede mejorarla. Imagina que estamos utilizando una clase y no tenemos el c&#xF3;digo fuente de la misma, y hay un problema con uno de sus m&#xE9;todos.</p>
<p>Si la clase es <em>final</em>, no podemos extenderla para sobrescribir el m&#xE9;todo y solucionar el problema. En otras palabras, perdemos la extensibilidad, uno de los beneficios de la programaci&#xF3;n orientada a objetos.</p>
<h2 id="span-name3-metodos-finalspan-3-m%C3%A9todos-final"><span name="3-metodos-final"></span> <a href="#3-metodos-final">3.</a> M&#xE9;todos <em>final</em></h2>
<p><strong>Los m&#xE9;todos marcados como <em>final</em> no pueden ser sobrescritos (override).</strong> Cuando dise&#xF1;amos una clase y sentimos que un m&#xE9;todo no debe ser sobrescrito, podemos hacer que este m&#xE9;todo sea <em>final</em>. Tambi&#xE9;n podemos encontrar muchos m&#xE9;todos finales en las bibliotecas centrales de Java.</p>
<p>A veces no necesitamos prohibir completamente la extensi&#xF3;n de una clase, sino solo evitar la sobrescritura de algunos m&#xE9;todos. Un buen ejemplo de esto es la clase <code>Thread</code>. Es legal extenderla y as&#xED; crear una clase de hilo personalizada. Pero su m&#xE9;todo <code>isAlive()</code> es <em>final</em>.</p>
<p>Este m&#xE9;todo comprueba si un hilo est&#xE1; vivo. Es imposible sobrescribir correctamente el m&#xE9;todo <code>isAlive()</code> por muchas razones. Una de ellas es que este m&#xE9;todo es nativo. El c&#xF3;digo nativo se implementa en otro lenguaje de programaci&#xF3;n y a menudo es espec&#xED;fico del sistema operativo y el hardware en el que se ejecuta.</p>
<p>Creemos una clase <code>Perro</code> y hagamos que su m&#xE9;todo <code>sonido()</code> sea <em>final</em>:</p>
<pre><code class="language-java">public class Perro {
    public final void sonido() {
        // ...
    }
}
</code></pre>
<p>Ahora extendamos la clase <code>Perro</code> e intentemos sobrescribir su m&#xE9;todo <code>sonido()</code>:</p>
<pre><code class="language-java">public class PerroNegro extends Perro {
    public void sonido() {
    }
}
</code></pre>
<p>Veremos el error del compilador:</p>
<pre><code>- overrides 
com.javamagician.final.Perro.sonido
- Cannot override the final method from Perro
sonido() method is final and can&#x2019;t be overridden
</code></pre>
<p>Si algunos m&#xE9;todos de nuestra clase son llamados por otros m&#xE9;todos, deber&#xED;amos considerar hacer que los m&#xE9;todos llamados sean <em>final</em>. De lo contrario, sobrescribirlos puede afectar el trabajo de los llamadores y causar resultados sorprendentes.</p>
<p>Si nuestro constructor llama a otros m&#xE9;todos, generalmente deber&#xED;amos declarar estos m&#xE9;todos como <em>final</em> por la raz&#xF3;n mencionada anteriormente.</p>
<p>&#xBF;Cu&#xE1;l es la diferencia entre hacer que todos los m&#xE9;todos de la clase sean <em>final</em> y marcar la clase en s&#xED; como <em>final</em>? En el primer caso, podemos extender la clase y agregar nuevos m&#xE9;todos a ella.</p>
<p>En el segundo caso, no podemos hacerlo.</p>
<h2 id="span-name4-variables-finalspan-4-variables-final"><span name="4-variables-final"></span> <a href="#4-variables-final">4.</a> Variables <em>final</em></h2>
<p><strong>Las variables marcadas como <em>final</em> no pueden ser reasignadas.</strong> Una vez que una variable <em>final</em> se inicializa, no se puede alterar.</p>
<h3 id="span-name4-1-variables-primitivas-finalspan-41-variables-primitivas-final"><span name="4-1-variables-primitivas-final"></span> <a href="#4-1-variables-primitivas-final">4.1</a>. Variables Primitivas <em>final</em></h3>
<p>Declaremos una variable primitiva <em>final</em> <code>i</code>, luego asignemos <code>0</code> a ella.</p>
<p>Y tratemos de asignarle un valor de <code>1</code>:</p>
<pre><code class="language-java">public void cuandoAsignamosVariableFinal_entoncesSoloUnaVez() {
    final int i = 0;
    // ...
    i = 1;
}
</code></pre>
<p>El compilador dice:</p>
<pre><code>The final local variable i may already have been assigned
</code></pre>
<h3 id="span-name4-2-variables-de-referencia-finalspan-42-variables-de-referencia-final"><span name="4-2-variables-de-referencia-final"></span> <a href="#4-2-variables-de-referencia-final">4.2</a>. Variables de Referencia <em>final</em></h3>
<p>Si tenemos una variable de referencia <em>final</em>, tampoco podemos reasignarla. Pero <strong>esto no significa que el objeto al que hace referencia sea inmutable</strong>. Podemos cambiar libremente las propiedades de este objeto.</p>
<p>Para demostrar esto, declaremos la variable de referencia <em>final</em> <code>gato</code> e inicialic&#xE9;mosla:</p>
<pre><code class="language-java">final Gato gato = new Gato();
</code></pre>
<p>Si intentamos reasignarla, veremos un error del compilador:</p>
<pre><code>The final local variable gato cannot be assigned. It must be blank and not using a compound assignment
</code></pre>
<p>Pero podemos cambiar las propiedades de la instancia de <code>Gato</code>:</p>
<pre><code class="language-java">gato.setPeso(4);

assertEquals(4, gato.getPeso());
</code></pre>
<h3 id="span-name4-3-campos-finalspan-43-campos-final"><span name="4-3-campos-final"></span> <a href="#4-3-campos-final">4.3</a>. Campos <em>final</em></h3>
<p><strong>Los campos final pueden ser constantes o campos de escritura &#xFA;nica</strong>. Para distinguirlos, debemos hacernos una pregunta: &#xBF;incluir&#xED;amos este campo si fu&#xE9;ramos a serializar el objeto? Si no, entonces no es parte del objeto, sino una constante.</p>
<p>Ten en cuenta que seg&#xFA;n las convenciones de nomenclatura, las constantes de clase deben estar en may&#xFA;sculas, con componentes separados por el car&#xE1;cter de subrayado (&quot;_&quot;):</p>
<pre><code class="language-java">static final int ANCHO_MAXIMO = 1337;
</code></pre>
<p>Ten en cuenta que <strong>cualquier campo <em>final</em> debe inicializarse antes de que el constructor se complete.</strong></p>
<p>Para campos <em>static</em> <em>final</em>, esto significa que podemos inicializarlos:</p>
<ul>
<li>al declararlos, como se muestra en el ejemplo anterior</li>
<li>en el bloque de inicializaci&#xF3;n est&#xE1;tica</li>
</ul>
<p>Para campos <em>final</em> de instancia, esto significa que podemos inicializarlos:</p>
<ul>
<li>al declararlos</li>
<li>en el bloque de inicializaci&#xF3;n de instancia</li>
<li>en el constructor</li>
</ul>
<p>De lo contrario, el compilador nos dar&#xE1; un error.</p>
<h3 id="span-name4-4-argumentos-finalspan-44-argumentos-final"><span name="4-4-argumentos-final"></span> <a href="#4-4-argumentos-final">4.4</a>. Argumentos <em>final</em></h3>
<p>La palabra clave <em>final</em> tambi&#xE9;n es legal para ponerla antes de los argumentos de un m&#xE9;todo. <strong>Un argumento <em>final</em> no se puede cambiar dentro de un m&#xE9;todo</strong>:</p>
<pre><code class="language-java">public void metodoConArgumentosFinales(final int x) {
    x = 0;
}
</code></pre>
<p>La asignaci&#xF3;n anterior provoca el error del compilador:</p>
<pre><code>The final local variable x cannot be assigned. It must be blank and not using a compound assignment
</code></pre>
<h2 id="span-name5-conclusionspan-5-conclusi%C3%B3n"><span name="5-conclusion"></span> <a href="#5-conclusion">5.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, aprendimos lo que significa la palabra clave <em>final</em> para clases, m&#xE9;todos y variables. Aunque es posible que no utilicemos la palabra clave <em>final</em> con frecuencia en nuestro c&#xF3;digo interno, puede ser una buena soluci&#xF3;n de dise&#xF1;o.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Polimorfismo en Java]]></title><description><![CDATA[Se requiere que todos los lenguajes de programación orientados a objetos (OOP) exhiban cuatro características básicas: abstracción, encapsulación, herencia y polimorfismo. En este artículo, veremos que es el polimorfismo en Java con ejemplos y cubrimos dos tipos fundamentales de polimorfismo.]]></description><link>https://javamagician.com/java-polimorfismo/</link><guid isPermaLink="false">65195d7ae9daa8aba62167c2</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Wed, 04 Oct 2023 23:17:54 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/10/java-polimorfismo_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introduccionspan-1-introducci%C3%B3n"><span name="1-introduccion"></span> <a href="#1-introduccion">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/10/java-polimorfismo_600x750.png" alt="Polimorfismo en Java"><p>Se requiere que todos los lenguajes de programaci&#xF3;n orientados a objetos (OOP) exhiban cuatro caracter&#xED;sticas b&#xE1;sicas: abstracci&#xF3;n, encapsulaci&#xF3;n, herencia y polimorfismo.</p>
<p>En este art&#xED;culo, cubrimos dos tipos fundamentales de polimorfismo: <strong>el polimorfismo est&#xE1;tico o de tiempo de compilaci&#xF3;n</strong> y <strong>el polimorfismo din&#xE1;mico o de tiempo de ejecuci&#xF3;n</strong>. El polimorfismo est&#xE1;tico se aplica durante la compilaci&#xF3;n, mientras que el polimorfismo din&#xE1;mico se realiza en tiempo de ejecuci&#xF3;n.</p>
<h2 id="span-name2-polimorfismo-estaticospan-2-polimorfismo-est%C3%A1tico"><span name="2-polimorfismo-estatico"></span> <a href="#2-polimorfismo-estatico">2.</a> Polimorfismo Est&#xE1;tico</h2>
<p>Seg&#xFA;n <a href="https://en.wikipedia.org/wiki/Template_metaprogramming?ref=javamagician.com#Static_polymorphism">Wikipedia</a>, el polimorfismo est&#xE1;tico es una imitaci&#xF3;n del <strong>polimorfismo que se resuelve en tiempo de compilaci&#xF3;n y, por lo tanto, elimina la necesidad de b&#xFA;squedas en tablas virtuales en tiempo de ejecuci&#xF3;n.</strong></p>
<p>Por ejemplo, nuestra clase <code>FicheroTexto</code> en una aplicaci&#xF3;n de gesti&#xF3;n de archivos puede tener tres m&#xE9;todos con la misma firma que el m&#xE9;todo <code>leer()</code>:</p>
<pre><code class="language-java">public class FicheroTexto extends FicheroGenerico {
    //...

    public String leer() {
        return this.getContent()
          .toString();
    }

    public String leer(int limite) {
        return this.getContent()
          .toString()
          .substring(0, limite);
    }

    public String leer(int inicio, int fin) {
        return this.getContent()
          .toString()
          .substring(inicio, fin);
    }
}
</code></pre>
<p>Durante la compilaci&#xF3;n del c&#xF3;digo, el compilador verifica que todas las invocaciones del m&#xE9;todo <code>leer</code> correspondan al menos a uno de los tres m&#xE9;todos definidos anteriormente.</p>
<h2 id="span-name3-polimorfismo-dinamicospan-3-polimorfismo-din%C3%A1mico"><span name="3-polimorfismo-dinamico"></span> <a href="#3-polimorfismo-dinamico">3.</a> Polimorfismo Din&#xE1;mico</h2>
<p>Con el polimorfismo din&#xE1;mico, la <strong>Java Virtual Machine (JVM) maneja la detecci&#xF3;n del m&#xE9;todo apropiado para ejecutar cuando una subclase se asigna a su forma principal</strong>. Esto es necesario porque la subclase puede anular algunos o todos los m&#xE9;todos definidos en la clase principal.</p>
<p>En una aplicaci&#xF3;n hipot&#xE9;tica de gesti&#xF3;n de archivos, definamos la clase principal para todos los archivos llamada <code>FicheroGenerico</code>:</p>
<pre><code class="language-java">public class FicheroGenerico {
    private String nombre;

    //...

    public String obtenerInformacion() {
        return &quot;Implementaci&#xF3;n de Fichero Gen&#xE9;rico&quot;;
    }
}
</code></pre>
<p>Tambi&#xE9;n podemos implementar una clase <code>FicheroImagen</code> que extiende <code>FicheroGenerico</code> pero anula el m&#xE9;todo <code>obtenerInformacion()</code> y agrega m&#xE1;s informaci&#xF3;n:</p>
<pre><code class="language-java">public class FicheroImagen extends FicheroGenerico {
    private int altura;
    private int ancho;

    //... m&#xE9;todos getter y setter
    
    public String obtenerInformacion() {
        return &quot;Implementaci&#xF3;n de Fichero de Imagen&quot;;
    }
}
</code></pre>
<p>Cuando creamos una instancia de <code>FicheroImagen</code> y la asignamos a una clase <code>FicheroGenerico</code>, se realiza una conversi&#xF3;n impl&#xED;cita. Sin embargo, la JVM mantiene una referencia a la forma real de <code>FicheroImagen</code>.</p>
<p><strong>La construcci&#xF3;n anterior es an&#xE1;loga a la anulaci&#xF3;n de m&#xE9;todos</strong>. Podemos confirmarlo invocando el m&#xE9;todo <code>obtenerInformacion()</code> de la siguiente manera:</p>
<pre><code class="language-java">public static void main(String[] args) {
    FicheroGenerico ficheroGenerico = new FicheroImagen(&quot;EjemploFicheroImagen&quot;, 200, 100, 
      new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB)
      .toString()
      .getBytes(), &quot;v1.0.0&quot;);
    logger.info(&quot;Informaci&#xF3;n del Fichero: \n&quot; + ficheroGenerico.obtenerInformacion());
}
</code></pre>
<p>Como era de esperar, <code>ficheroGenerico.obtenerInformacion()</code> activa el m&#xE9;todo <code>obtenerInformacion()</code> de la clase <code>FicheroImagen</code>, como se ve en la salida a continuaci&#xF3;n:</p>
<pre><code>Informaci&#xF3;n del Fichero: 
Implementaci&#xF3;n de Fichero de Imagen
</code></pre>
<h2 id="span-name4-otras-caracteristicas-polimorficas-en-javaspan-4-otras-caracter%C3%ADsticas-polim%C3%B3rficas-en-java"><span name="4-otras-caracteristicas-polimorficas-en-java"></span> <a href="#4-otras-caracteristicas-polimorficas-en-java">4.</a> Otras Caracter&#xED;sticas Polim&#xF3;rficas en Java</h2>
<p>Adem&#xE1;s de estos dos tipos principales de polimorfismo en Java, existen otras caracter&#xED;sticas en el lenguaje de programaci&#xF3;n Java que exhiben polimorfismo. Discutamos algunas de estas caracter&#xED;sticas.</p>
<h3 id="span-name4-1-coercionspan-41-coerci%C3%B3n"><span name="4-1-coercion"></span> <a href="#4-1-coercion">4.1.</a> Coerci&#xF3;n</h3>
<p>La coerci&#xF3;n polim&#xF3;rfica trata sobre la conversi&#xF3;n impl&#xED;cita de tipo realizada por el compilador para evitar errores de tipo. Un ejemplo t&#xED;pico se ve en la concatenaci&#xF3;n de un entero y una cadena:</p>
<pre><code class="language-java">String cadena = &quot;cadena&quot; + 2;
</code></pre>
<h3 id="span-name4-2-sobrecarga-de-operadoresspan-42-sobrecarga-de-operadores"><span name="4-2-sobrecarga-de-operadores"></span> <a href="#4-2-sobrecarga-de-operadores">4.2.</a> Sobrecarga de Operadores</h3>
<p>La sobrecarga de operadores o m&#xE9;todos se refiere a una caracter&#xED;stica polim&#xF3;rfica en la que un mismo s&#xED;mbolo u operador tiene diferentes significados (formas) seg&#xFA;n el contexto.</p>
<p>Por ejemplo, el s&#xED;mbolo de suma (+) se puede usar tanto para la adici&#xF3;n matem&#xE1;tica como para la concatenaci&#xF3;n de <em>Strings</em>. En ambos casos, solo el contexto (es decir, los tipos de argumentos) determina la interpretaci&#xF3;n del s&#xED;mbolo:</p>
<pre><code class="language-java">String cadena = &quot;2&quot; + 2;
int suma = 2 + 2;
System.out.printf(&quot; cadena = %s\n suma = %d\n&quot;, cadena, suma);
</code></pre>
<p>Salida:</p>
<pre><code>cadena = 22
suma = 4
</code></pre>
<h3 id="span-name4-3-parametros-polimorficosspan-43-par%C3%A1metros-polim%C3%B3rficos"><span name="4-3-parametros-polimorficos"></span> <a href="#4-3-parametros-polimorficos">4.3.</a> Par&#xE1;metros Polim&#xF3;rficos</h3>
<p>El polimorfismo param&#xE9;trico permite que el nombre de un par&#xE1;metro o m&#xE9;todo en una clase se asocie con diferentes tipos. Tenemos un ejemplo t&#xED;pico a continuaci&#xF3;n, donde definimos <code>contenido</code> como una <em>String</em> y luego como un <em>Integer</em>:</p>
<pre><code class="language-java">public class FicheroTexto extends FicheroGenerico {
    private String contenido;
    
    public String establecerDelimitadorDeContenido() {
        int contenido = 100;
        this.contenido = this.contenido + contenido;
    }
}
</code></pre>
<p>Tambi&#xE9;n es importante tener en cuenta que <strong>la declaraci&#xF3;n de par&#xE1;metros polim&#xF3;rficos puede llevar a un problema conocido como &quot;variable hiding&quot; (ocultaci&#xF3;n de variables)</strong>, donde la declaraci&#xF3;n local de un par&#xE1;metro siempre anula la declaraci&#xF3;n global de otro par&#xE1;metro con el mismo nombre.</p>
<p>Para resolver este problema, a menudo es aconsejable utilizar referencias globales, como la palabra clave <em>this</em>, para se&#xF1;alar variables globales dentro de un contexto local.</p>
<h3 id="span-name4-4-subtipos-polimorficosspan-44-subtipos-polim%C3%B3rficos"><span name="4-4-subtipos-polimorficos"></span> <a href="#4-4-subtipos-polimorficos">4.4.</a> Subtipos Polim&#xF3;rficos</h3>
<p>El subtipo polim&#xF3;rfico permite asignar varios subtipos a un tipo y esperar que todas las invocaciones en el tipo activen las definiciones disponibles en el subtipo.</p>
<p>Por ejemplo, si tenemos una colecci&#xF3;n de <code>FicheroGenerico</code> y llamamos al m&#xE9;todo <code>obtenerInformacion()</code> en cada uno de ellos, podemos esperar que la salida sea diferente seg&#xFA;n el subtipo del que se deriv&#xF3; cada elemento en la colecci&#xF3;n:</p>
<pre><code class="language-java">FicheroGenerico [] ficheros = {new FicheroImagen(&quot;EjemploFicheroImagen&quot;, 200, 100, 
  new BufferedImage(100, 200, BufferedImage.TYPE_INT_RGB).toString() 
  .getBytes(), &quot;v1.0.0&quot;), new FicheroTexto(&quot;EjemploFicheroTexto&quot;, 
  &quot;Este es un contenido de texto de ejemplo&quot;, &quot;v1.0.0&quot;)};
 
for (int i = 0; i &lt; ficheros.length; i++) {
    ficheros[i].obtenerInformacion();
}
</code></pre>
<p><strong>El polimorfismo de subtipo se hace posible mediante una combinaci&#xF3;n de conversi&#xF3;n ascendente y enlace tard&#xED;o</strong>. La conversi&#xF3;n ascendente implica la conversi&#xF3;n de la jerarqu&#xED;a de herencia de un supertipo a un subtipo:</p>
<pre><code class="language-java">FicheroImagen ficheroImagen = new FicheroImagen();
FicheroGenerico fichero = ficheroImagen;
</code></pre>
<p>El efecto resultante de lo anterior es que los m&#xE9;todos espec&#xED;ficos de <code>FicheroImagen</code> no se pueden invocar en el nuevo <code>FicheroGenerico</code> convertido hacia arriba. Sin embargo, los m&#xE9;todos en el subtipo anulan los m&#xE9;todos similares definidos en el supertipo.</p>
<p>Para resolver el problema de no poder invocar m&#xE9;todos espec&#xED;ficos del subtipo al convertir hacia arriba a un supertipo, podemos hacer una conversi&#xF3;n hacia abajo de la herencia de un supertipo a un subtipo. Esto se hace mediante:</p>
<pre><code class="language-java">FicheroImagen ficheroImagen = (FicheroImagen) fichero;
</code></pre>
<p><strong>La estrategia de enlace tard&#xED;o ayuda al compilador a resolver cu&#xE1;l m&#xE9;todo activar despu&#xE9;s de la conversi&#xF3;n hacia arriba (upcasting)</strong>. En el caso de <code>ficheroImagen.obtenerInformacion</code> frente a <code>fichero.obtenerInformacion</code> en el ejemplo anterior, el compilador mantiene una referencia al m&#xE9;todo <code>obtenerInformacion</code> de <code>FicheroImagen</code>.</p>
<h2 id="span-name5-problemas-con-el-polimorfismospan-5-problemas-con-el-polimorfismo"><span name="5-problemas-con-el-polimorfismo"></span> <a href="#5-problemas-con-el-polimorfismo">5.</a> Problemas con el Polimorfismo</h2>
<p>Echemos un vistazo a algunas ambig&#xFC;edades en el polimorfismo que podr&#xED;an llevar a errores en tiempo de ejecuci&#xF3;n si no se verifican adecuadamente.</p>
<h3 id="span-name5-1-identificacion-de-tipo-durante-la-conversion-hacia-abajospan-51-identificaci%C3%B3n-de-tipo-durante-la-conversi%C3%B3n-hacia-abajo"><span name="5-1-identificacion-de-tipo-durante-la-conversion-hacia-abajo"></span> <a href="#5-1-identificacion-de-tipo-durante-la-conversion-hacia-abajo">5.1.</a> Identificaci&#xF3;n de Tipo Durante la Conversi&#xF3;n Hacia Abajo</h3>
<p>Recuerda que anteriormente perdimos el acceso a algunos m&#xE9;todos espec&#xED;ficos del subtipo despu&#xE9;s de realizar una conversi&#xF3;n hacia arriba. Aunque pudimos resolver esto con una conversi&#xF3;n hacia abajo, esto no garantiza una verificaci&#xF3;n real del tipo.</p>
<p>Por ejemplo, si realizamos una conversi&#xF3;n hacia arriba y luego una conversi&#xF3;n hacia abajo:</p>
<pre><code class="language-java">FicheroGenerico fichero = new FicheroGenerico();
FicheroImagen ficheroImagen = (FicheroImagen) fichero;
System.out.println(ficheroImagen.getAltura());
</code></pre>
<p>Notamos que el compilador permite una conversi&#xF3;n hacia abajo de un <code>FicheroGenerico</code> a un <code>FicheroImagen</code>, incluso cuando la clase en realidad es un <code>FicheroGenerico</code> y no un <code>FicheroImagen</code>.</p>
<p>En consecuencia, si intentamos invocar el m&#xE9;todo <code>getAltura()</code> en la clase <code>ficheroImagen</code>, obtenemos una excepci&#xF3;n de ClassCastException ya que <code>FicheroGenerico</code> no define el m&#xE9;todo <code>getAltura</code>:</p>
<pre><code>Excepci&#xF3;n en el subproceso &quot;main&quot; java.lang.ClassCastException:
FicheroGenerico no se puede convertir en FicheroImagen
</code></pre>
<p>Para resolver este problema, la JVM realiza una verificaci&#xF3;n de informaci&#xF3;n de tipo en tiempo de ejecuci&#xF3;n (siglas en ingl&#xE9;s RTTI). Tambi&#xE9;n podemos intentar una identificaci&#xF3;n expl&#xED;cita del tipo utilizando la palabra clave <em>instanceof</em> de la siguiente manera:</p>
<pre><code class="language-java">FicheroImagen ficheroImagen;
if (fichero instanceof FicheroImagen) {
    ficheroImagen = (FicheroImagen) fichero;
}
</code></pre>
<p>Lo anterior ayuda a evitar una excepci&#xF3;n de <code>ClassCastException</code> en tiempo de ejecuci&#xF3;n. Otra opci&#xF3;n que se puede usar es envolver la conversi&#xF3;n dentro de un bloque try-catch y capturar la excepci&#xF3;n de <code>ClassCastException</code>.</p>
<p>Es importante tener en cuenta que <strong>la verificaci&#xF3;n de RTTI es costosa</strong> debido al tiempo y los recursos necesarios para verificar eficazmente que un tipo sea correcto. Adem&#xE1;s, el uso frecuente de la palabra clave <em>instanceof</em> generalmente implica un dise&#xF1;o deficiente.</p>
<h3 id="span-name5-2-problema-de-la-clase-base-fragilspan-52-problema-de-la-clase-base-fr%C3%A1gil"><span name="5-2-problema-de-la-clase-base-fragil"></span> <a href="#5-2-problema-de-la-clase-base-fragil">5.2.</a> Problema de la Clase Base Fr&#xE1;gil</h3>
<p>Seg&#xFA;n <a href="https://en.wikipedia.org/wiki/Fragile_base_class?ref=javamagician.com">Wikipedia</a>, las clases base o superclases se consideran fr&#xE1;giles si las modificaciones aparentemente seguras en una clase base pueden hacer que las clases derivadas funcionen incorrectamente.</p>
<p>Consideremos una declaraci&#xF3;n de una superclase llamada <code>FicheroGenerico</code> y su subclase <code>FicheroTexto</code>:</p>
<pre><code class="language-java">public class FicheroGenerico {
    private String contenido;

    void escribirContenido(String contenido) {
        this.contenido = contenido;
    }
    void toString(String str) {
        str.toString();
    }
}

public class FicheroTexto extends FicheroGenerico {
    @Override
    void escribirContenido(String contenido) {
        toString(contenido);
    }
}
</code></pre>
<p>Cuando modificamos la clase <code>FicheroGenerico</code> de la siguiente manera:</p>
<pre><code class="language-java">public class FicheroGenerico {
    //...

    void toString(String str) {
        escribirContenido(str);
    }
}
</code></pre>
<p>Observamos que la modificaci&#xF3;n anterior deja a <code>FicheroTexto</code> en una recursi&#xF3;n infinita en el m&#xE9;todo <code>escribirContenido()</code>, lo que eventualmente provoca un desbordamiento de la pila.</p>
<p>Para abordar un problema de clase base fr&#xE1;gil, podemos usar la palabra clave <em>final</em> para evitar que las subclases anulen el m&#xE9;todo <code>escribirContenido()</code>. La documentaci&#xF3;n adecuada tambi&#xE9;n puede ayudar. Y, por &#xFA;ltimo, la composici&#xF3;n generalmente debe preferirse sobre la herencia.</p>
<h2 id="span-name6-conclusionspan-6-conclusi%C3%B3n"><span name="6-conclusion"></span> <a href="#6-conclusion">6.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, discutimos el concepto fundamental del polimorfismo, centr&#xE1;ndonos en ventajas y desventajas.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Clases Abstractas en Java]]></title><description><![CDATA[Existen muchos casos en los que, al implementar un contrato, deseamos posponer algunas partes de la implementación para completarlas más tarde. Esto se puede lograr en Java a través de las clases abstractas. Aprenderemos los conceptos básicos de las clases abstractas en Java.]]></description><link>https://javamagician.com/java-clases-abstractas/</link><guid isPermaLink="false">65185ec9da6d258ce15f56f1</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Sat, 30 Sep 2023 20:12:34 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/09/java-clases-abstractas_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/09/java-clases-abstractas_600x750.png" alt="Clases Abstractas en Java"><p>Existen muchos casos en los que, al implementar un contrato, deseamos posponer algunas partes de la implementaci&#xF3;n para completarlas m&#xE1;s tarde. Esto se puede lograr f&#xE1;cilmente en Java a trav&#xE9;s de las clases abstractas.</p>
<p><strong>En este tutorial, aprenderemos los conceptos b&#xE1;sicos de las clases abstractas en Java y en qu&#xE9; casos pueden ser &#xFA;tiles.</strong></p>
<h2 id="span-name2-conceptos-clave-para-clases-abstractasspan-2-conceptos-clave-para-clases-abstractas"><span name="2-conceptos-clave-para-clases-abstractas"></span> <a href="#2-conceptos-clave-para-clases-abstractas">2.</a> Conceptos Clave para Clases Abstractas</h2>
<p>Antes de profundizar en cu&#xE1;ndo usar una clase abstracta, <strong>veamos sus caracter&#xED;sticas m&#xE1;s relevantes</strong>:</p>
<ul>
<li><strong>Definimos una clase abstracta con el modificador <em>abstract</em> que precede a la palabra clave <em>class</em></strong>.</li>
<li>Se puede heredar de una clase abstracta, pero no se puede instanciar.</li>
<li>Si una clase define uno o m&#xE1;s m&#xE9;todos <em>abstract</em>, entonces la clase en s&#xED; debe declararse como <em>abstract</em>.</li>
<li><strong>Una clase <em>abstract</em> puede declarar m&#xE9;todos tanto abstractos como concretos.</strong></li>
<li>Una subclase derivada de una clase <em>abstract</em> debe implementar todos los m&#xE9;todos <em>abstract</em> de la clase base o ser ella misma <em>abstract</em>.</li>
</ul>
<p>Para comprender mejor estos conceptos, crearemos un ejemplo simple.</p>
<p>Supongamos que nuestra clase abstracta base define la API abstracta de un juego de mesa:</p>
<pre><code class="language-java">public abstract class JuegoDeMesa {

    //... declaraciones de campos, constructores

    public abstract void jugar();

    //... m&#xE9;todos concretos
}
</code></pre>
<p>Luego, podemos crear una subclase que implemente el m&#xE9;todo <code>jugar</code>:</p>
<pre><code class="language-java">public class Damas extends JuegoDeMesa {

    public void jugar() {
        //... implementaci&#xF3;n
    }
}
</code></pre>
<h2 id="span-name3-cuando-usar-clases-abstractasspan-3-cu%C3%A1ndo-usar-clases-abstractas"><span name="3-cuando-usar-clases-abstractas"></span> <a href="#3-cuando-usar-clases-abstractas">3.</a> Cu&#xE1;ndo Usar Clases Abstractas</h2>
<p>Ahora, <strong>analicemos algunos escenarios t&#xED;picos en los que deber&#xED;amos preferir las clases abstractas sobre interfaces</strong> y clases concretas:</p>
<ul>
<li>Queremos encapsular alguna funcionalidad com&#xFA;n en un solo lugar (reutilizaci&#xF3;n de c&#xF3;digo) que m&#xFA;ltiples subclases relacionadas compartir&#xE1;n.</li>
<li>Necesitamos definir parcialmente una API que nuestras subclases puedan ampliar y refinar f&#xE1;cilmente.</li>
<li>Las subclases necesitan heredar uno o m&#xE1;s m&#xE9;todos o campos comunes con modificadores de acceso protegidos.</li>
</ul>
<p>Es importante tener en cuenta que todos estos escenarios son buenos ejemplos de adherencia completa basada en herencia al <a href="https://es.wikipedia.org/wiki/Principio_de_abierto/cerrado?ref=javamagician.com">principio de Abierto/Cerrado.</a></p>
<p>Adem&#xE1;s, dado que el uso de clases abstractas trata impl&#xED;citamente con tipos base y subtipos, tambi&#xE9;n estamos aprovechando el <a href="https://javamagician.com/java-polimorfismo/">polimorfismo</a>.</p>
<p>Ten en cuenta que la reutilizaci&#xF3;n de c&#xF3;digo es una raz&#xF3;n muy convincente para usar clases abstractas, siempre y cuando se preserve la relaci&#xF3;n &quot;es un&quot; dentro de la jerarqu&#xED;a de clases.</p>
<p>Desde Java 8 se agreg&#xF3; otro matiz con <strong><a href="https://javamagician.com/java-metodos-static-default/">los m&#xE9;todos por defecto (<em>default</em>)</a>, que a veces pueden reemplazar la necesidad de crear una clase abstracta por completo</strong>.</p>
<h2 id="span-name4-ejemplo-de-jerarquia-de-lectores-de-archivosspan-4-ejemplo-de-jerarqu%C3%ADa-de-lectores-de-archivos"><span name="4-ejemplo-de-jerarquia-de-lectores-de-archivos"></span> <a href="#4-ejemplo-de-jerarquia-de-lectores-de-archivos">4.</a> Ejemplo de Jerarqu&#xED;a de Lectores de Archivos</h2>
<p>Para comprender con mayor claridad la funcionalidad que aportan las clases abstractas, veamos otro ejemplo.</p>
<h3 id="span-name4-1-definir-una-clase-abstracta-basespan-41-definir-una-clase-abstracta-base"><span name="4-1-definir-una-clase-abstracta-base"></span> <a href="#4-1-definir-una-clase-abstracta-base">4.1</a> Definir una Clase Abstracta Base</h3>
<p>Entonces, si quisi&#xE9;ramos tener varios tipos de lectores de archivos, podr&#xED;amos crear una clase abstracta que encapsule lo que es com&#xFA;n en la lectura de archivos:</p>
<pre><code class="language-java">public abstract class LectorDeArchivoBase {
    
    protected Path rutaArchivo;
    
    protected LectorDeArchivoBase(Path rutaArchivo) {
        this.rutaArchivo = rutaArchivo;
    }
    
    public Path obtenerRutaArchivo() {
        return rutaArchivo;
    }
    
    public List&lt;String&gt; leerArchivo() throws IOException {
        return Files.lines(rutaArchivo)
          .map(this::mapearLineaArchivo).collect(Collectors.toList());
    }
    
    protected abstract String mapearLineaArchivo(String linea);
}
</code></pre>
<p>Observa que hemos declarado <code>rutaArchivo</code> como protegida para que las subclases puedan acceder a ella si es necesario. M&#xE1;s importante a&#xFA;n, <strong>hemos dejado algo sin hacer: c&#xF3;mo analizar realmente una l&#xED;nea de texto</strong> del contenido del archivo.</p>
<p>Nuestro plan es simple: si nuestras clases concretas no tienen una forma especial de almacenar la ruta del archivo o de recorrer el archivo, cada una tendr&#xE1; una forma especial de transformar cada l&#xED;nea.</p>
<p>A simple vista, <code>LectorDeArchivoBase</code> puede parecer innecesario. Sin embargo, es la base de un dise&#xF1;o limpio y f&#xE1;cilmente ampliable. A partir de &#xE9;l, <strong>podemos implementar f&#xE1;cilmente diferentes versiones de un lector de archivos que pueden centrarse en su l&#xF3;gica de negocio &#xFA;nica.</strong></p>
<h3 id="span-name4-2-definir-subclasesspan-42-definir-subclases"><span name="4-2-definir-subclases"></span> <a href="#4-2-definir-subclases">4.2</a> Definir Subclases</h3>
<p>Una implementaci&#xF3;n natural es probablemente una que convierte el contenido del archivo a min&#xFA;sculas:</p>
<pre><code class="language-java">public class LectorDeArchivoMinusculas extends LectorDeArchivoBase {

    public LectorDeArchivoMinusculas(Path rutaArchivo) {
        super(rutaArchivo);
    }

    @Override
    protected String mapearLineaArchivo(String linea) {
        return linea.toLowerCase();
    }   
}
</code></pre>
<p>Otra podr&#xED;a ser una que convierte el contenido del archivo a may&#xFA;sculas:</p>
<pre><code class="language-java">public class LectorDeArchivoMayusculas extends LectorDeArchivoBase {

    public LectorDeArchivoMayusculas(Path rutaArchivo) {
        super(rutaArchivo);
    }

    @Override
    protected String mapearLineaArchivo(String linea) {
        return linea.toUpperCase();
    }
}
</code></pre>
<p>Como podemos ver en este ejemplo simple, <strong>cada subclase puede centrarse en su comportamiento &#xFA;nico</strong> sin necesidad de especificar otros aspectos de la lectura de archivos.</p>
<h3 id="span-name4-3-uso-de-una-subclasespan-43-uso-de-una-subclase"><span name="4-3-uso-de-una-subclase"></span> <a href="#4-3-uso-de-una-subclase">4.3</a> Uso de una Subclase</h3>
<p>Finalmente, usar una clase que hereda de una clase abstracta no es diferente a cualquier otra clase concreta:</p>
<pre><code class="language-java">@Test
public void dadoUnainstanciaDeLectorDeArchivoMinusculas_cuandoSeLlamaLeerArchivo_entoncesEsCorrecto() throws Exception {
    URL ubicacion = getClass().getClassLoader().getResource(&quot;files/test.txt&quot;)
    Path ruta = Paths.get(ubicaci&#xF3;n.toURI());
    LectorDeArchivoBase lectorMinusculas = new LectorDeArchivoMinusculas(ruta);
        
    assertThat(lectorMinusculas.leerArchivo()).isInstanceOf(List.class);
}
</code></pre>
<p>Por simplificaci&#xF3;n, el archivo de destino se encuentra en la carpeta <code>src/main/resources/files</code>. Por lo tanto, utilizamos un cargador de clases de aplicaci&#xF3;n para obtener la ruta del archivo de ejemplo. Profundizaremos m&#xE1;s en los cargadores de clases en futuras lecciones.</p>
<h2 id="span-name5-conclusionspan-5-conclusi%C3%B3n"><span name="5-conclusion"></span> <a href="#5-conclusion">5.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo r&#xE1;pido, <strong>aprendimos los conceptos b&#xE1;sicos de las clases abstractas en Java y cu&#xE1;ndo usarlas para lograr la abstracci&#xF3;n y encapsular la implementaci&#xF3;n com&#xFA;n en un solo lugar.</strong></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Guía de Inicialización de Objetos en Java]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<p>En pocas palabras, antes de que podamos trabajar con un objeto en la JVM (Java Virtual Machine), debe inicializarse.</p>
<p>En este tutorial, examinaremos las diversas formas en que podemos inicializar tipos primitivos y objetos.</p>
<h2 id="span-name2-declaracion-vs-inicializacionspan-2-declaraci%C3%B3n-vs-inicializaci%C3%B3n"><span name="2-declaracion-vs-inicializacion"></span> <a href="#2-declaracion-vs-inicializacion">2.</a> Declaraci&#xF3;n vs. Inicializaci&#xF3;n</h2>
<p>Comencemos asegur&#xE1;ndonos</p>]]></description><link>https://javamagician.com/java-inicializacion-objetos/</link><guid isPermaLink="false">6512e876da6d258ce15f55a6</guid><category><![CDATA[Lenguaje Java]]></category><category><![CDATA[Programación Orientada a Objetos]]></category><dc:creator><![CDATA[The Java Magician]]></dc:creator><pubDate>Thu, 28 Sep 2023 00:11:49 GMT</pubDate><media:content url="https://javamagician.com/content/images/2023/09/java-inicializacion-objetos_600x750.png" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h2 id="span-name1-introspan-1-introducci%C3%B3n"><span name="1-intro"></span> <a href="#1-intro">1.</a> Introducci&#xF3;n</h2>
<img src="https://javamagician.com/content/images/2023/09/java-inicializacion-objetos_600x750.png" alt="Gu&#xED;a de Inicializaci&#xF3;n de Objetos en Java"><p>En pocas palabras, antes de que podamos trabajar con un objeto en la JVM (Java Virtual Machine), debe inicializarse.</p>
<p>En este tutorial, examinaremos las diversas formas en que podemos inicializar tipos primitivos y objetos.</p>
<h2 id="span-name2-declaracion-vs-inicializacionspan-2-declaraci%C3%B3n-vs-inicializaci%C3%B3n"><span name="2-declaracion-vs-inicializacion"></span> <a href="#2-declaracion-vs-inicializacion">2.</a> Declaraci&#xF3;n vs. Inicializaci&#xF3;n</h2>
<p>Comencemos asegur&#xE1;ndonos de que estamos en la misma p&#xE1;gina.</p>
<p><strong>La declaraci&#xF3;n es el proceso de definir la variable</strong>, junto con su tipo y nombre.</p>
<p>Aqu&#xED; estamos declarando la variable <code>id</code>:</p>
<pre><code class="language-java">int id;
</code></pre>
<p><strong>La inicializaci&#xF3;n, por otro lado, se trata de asignar un valor:</strong></p>
<pre><code class="language-java">id = 1;
</code></pre>
<p>Para demostrarlo, crearemos una clase <code>Usuario</code> con propiedades de <code>nombre</code> e <code>id</code>:</p>
<pre><code class="language-java">public class Usuario {
    private String nombre;
    private int id;
    
    // constructor est&#xE1;ndar, getters, setters, etc.
}
</code></pre>
<p>A continuaci&#xF3;n, veremos que la inicializaci&#xF3;n funciona de manera diferente seg&#xFA;n el tipo de campo que estemos inicializando.</p>
<h2 id="span-name3-objetos-vs-tipos-primitivosspan-3-objetos-vs-tipos-primitivos"><span name="3-objetos-vs-tipos-primitivos"></span> <a href="#3-objetos-vs-tipos-primitivos">3.</a> Objetos vs. Tipos Primitivos</h2>
<p>Java proporciona dos tipos de representaci&#xF3;n de datos: tipos primitivos y tipos de referencia. En esta secci&#xF3;n, discutiremos las diferencias entre los dos en relaci&#xF3;n con la inicializaci&#xF3;n.</p>
<p>Java tiene ocho tipos de datos incorporados, conocidos como tipos primitivos de Java; las variables de este tipo mantienen sus valores directamente.</p>
<p>Los tipos de referencia mantienen referencias a objetos (instancias de clases). <strong>A diferencia de los tipos primitivos que mantienen sus valores en la memoria donde se asigna la variable, las referencias no mantienen el valor del objeto al que se refieren.</strong></p>
<p>En su lugar, <strong>una referencia apunta a un objeto almacenando la direcci&#xF3;n de memoria donde se encuentra el objeto.</strong></p>
<p>Ten en cuenta que Java no nos permite descubrir cu&#xE1;l es la direcci&#xF3;n de memoria f&#xED;sica. En cambio, solo podemos usar la referencia para referirnos al objeto.</p>
<p>Veamos un ejemplo que declara e inicializa un tipo de referencia de nuestra clase <code>Usuario</code>:</p>
<pre><code class="language-java">@Test
public void cuandoSeInicializaConNew_entoncesLaInstanciaNoEsNula() {
    Usuario usuario = new Usuario();
 
    assertThat(usuario).isNotNull();
}
</code></pre>
<p>Como podemos ver, una referencia se puede asignar a un nuevo objeto utilizando la palabra clave <em>new</em>, que es responsable de crear el nuevo objeto <code>Usuario</code>.</p>
<p>Continuemos aprendiendo m&#xE1;s sobre la creaci&#xF3;n de objetos.</p>
<h2 id="span-name4-creacion-objetosspan-4-creaci%C3%B3n-de-objetos"><span name="4-creacion-objetos"></span> <a href="#4-creacion-objetos">4.</a> Creaci&#xF3;n de Objetos</h2>
<p>A diferencia de los tipos primitivos, la creaci&#xF3;n de objetos es un poco m&#xE1;s compleja. Esto se debe a que no estamos agregando simplemente el valor al campo; en su lugar, activamos la inicializaci&#xF3;n utilizando la palabra clave <em>new</em>. Esto, a su vez, invoca a un constructor e inicializa el objeto en la memoria.</p>
<p>Hablemos m&#xE1;s detenidamente sobre los constructores y la palabra clave <em>new</em>.</p>
<p>La palabra clave <em>new</em> es <strong>responsable de asignar memoria para el nuevo objeto a trav&#xE9;s de un constructor.</strong></p>
<p><strong>Normalmente, un constructor se usa para inicializar las variables de instancia que representan las propiedades principales del objeto creado.</strong></p>
<p>Si no proporcionamos un constructor expl&#xED;citamente, el compilador crear&#xE1; un constructor predeterminado que no tiene argumentos y simplemente asigna memoria para el objeto.</p>
<p><strong>Una clase puede tener muchos constructores, siempre y cuando las listas de par&#xE1;metros sean diferentes (sobrecarga o overload)</strong>. Cada constructor que no llama a otro constructor en la misma clase tiene una llamada a su constructor principal, ya sea que se haya escrito expl&#xED;citamente o que lo haya insertado el compilador a trav&#xE9;s de <em>super()</em>.</p>
<p>Agreguemos un constructor a nuestra clase <code>Usuario</code>:</p>
<pre><code class="language-java">public Usuario(String nombre, int id) {
    this.nombre = nombre;
    this.id = id;
}
</code></pre>
<p>Ahora podemos usar nuestro constructor para crear un objeto <code>Usuario</code> con valores iniciales para sus propiedades:</p>
<pre><code class="language-java">Usuario usuario = new Usuario(&quot;Alice&quot;, 1);
</code></pre>
<h2 id="span-name5-alcance-variablesspan-5-alcance-de-las-variables"><span name="5-alcance-variables"></span> <a href="#5-alcance-variables">5.</a> Alcance de las Variables</h2>
<p>En las siguientes secciones, veremos los diferentes tipos de alcance (<em>scope</em>) en los que una variable en Java puede existir y c&#xF3;mo esto afecta al proceso de inicializaci&#xF3;n.</p>
<h3 id="span-name5-1-variables-de-instancia-y-clasespan-51-variables-de-instancia-y-de-clase"><span name="5-1-variables-de-instancia-y-clase"></span> <a href="#5-1-variables-de-instancia-y-clase">5.1</a>. Variables de Instancia y de Clase</h3>
<p><strong>Las variables de instancia y de clase no requieren que las inicialicemos.</strong> Tan pronto como declaramos estas variables, se les asigna un valor predeterminado:</p>
<table style="background: none">
    <thead>
        <tr>
            <th style="background-color: #667799;color: white;">Tipo</th>
            <th style="background-color: #667799;color: white;">Valor por defecto</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>boolean</td>
            <td>false</td>
        </tr>
        <tr>
            <td>byte, short, int, long</td>
            <td>0</td>
        </tr>
        <tr>
            <td>float, doble</td>
            <td>0.0</td>
        </tr>
        <tr>
            <td>char</td>
            <td>&apos;\u0000&apos;</td>
        </tr>
        <tr>
            <td>Tipo de referencia</td>
            <td>null</td>
        </tr>
    </tbody>
</table>
<p>Ahora intentemos definir algunas variables relacionadas con instancias y clases, y comprobemos si tienen un valor predeterminado o no:</p>
<pre><code class="language-java">@Test
public void cuandoLosValoresNoSeInicializan_entoncesElNombreDeUsuarioYElIdDevuelvenElPredeterminado() {
    Usuario usuario = new Usuario();
 
    assertThat(usuario.getNombre()).isNull();
    assertThat(usuario.getId() == 0);
}
</code></pre>
<h3 id="span-name5-2-variables-localesspan-52-variables-locales"><span name="5-2-variables-locales"></span> <a href="#5-2-variables-locales">5.2</a>. Variables Locales</h3>
<p><strong>Las variables locales deben inicializarse antes de su uso</strong>, ya que no tienen un valor predeterminado y el compilador no nos permitir&#xE1; usar un valor no inicializado.</p>
<p>Por ejemplo, el siguiente c&#xF3;digo genera un error del compilador:</p>
<pre><code class="language-java">public void imprimir(){
    int i;
    System.out.println(i);
}
</code></pre>
<h2 id="span-name6-la-palabra-clave-finalspan-6-la-palabra-clave-final"><span name="6-la-palabra-clave-final"></span> <a href="#6-la-palabra-clave-final">6.</a> La Palabra Clave <em>final</em></h2>
<p>La palabra clave <em>final</em> aplicada a un campo significa que el valor del campo ya no se puede cambiar despu&#xE9;s de la inicializaci&#xF3;n. De esta manera, podemos definir constantes en Java.</p>
<p>Agreguemos una constante a nuestra clase <code>Usuario</code>:</p>
<pre><code class="language-java">private static final int ANYO = 2000;
</code></pre>
<p>Las constantes deben inicializarse ya sea cuando se declaran o en un constructor.</p>
<h2 id="span-name7-inicializadores-en-javaspan-7-inicializadores-en-java"><span name="7-inicializadores-en-java"></span> <a href="#7-inicializadores-en-java">7.</a> Inicializadores en Java</h2>
<p>En Java, un <strong>inicializador es un bloque de c&#xF3;digo que no tiene un nombre o tipo de datos asociado</strong> y se coloca fuera de cualquier m&#xE9;todo, constructor o bloque de c&#xF3;digo.</p>
<p>Java ofrece dos tipos de inicializadores, inicializadores est&#xE1;ticos e inicializadores de instancia. Veamos c&#xF3;mo podemos usar cada uno de ellos.</p>
<h3 id="span-name7-1-inicializadores-de-instanciaspan-71-inicializadores-de-instancia"><span name="7-1-inicializadores-de-instancia"></span> <a href="#7-1-inicializadores-de-instancia">7.1</a>. Inicializadores de Instancia</h3>
<p>Podemos usar estos para inicializar variables de instancia.</p>
<p>Para demostrarlo, proporcionaremos un valor para un <code>id</code> de usuario utilizando un inicializador de instancia en nuestra clase <code>Usuario</code>:</p>
<pre><code class="language-java">{
    id = 0;
}
</code></pre>
<h3 id="span-name7-2-bloque-de-inicializacion-estaticaspan-72-bloque-de-inicializaci%C3%B3n-est%C3%A1tica"><span name="7-2-bloque-de-inicializacion-estatica"></span> <a href="#7-2-bloque-de-inicializacion-estatica">7.2</a>. Bloque de Inicializaci&#xF3;n Est&#xE1;tica</h3>
<p>Un inicializador est&#xE1;tico, o bloque est&#xE1;tico, es un bloque de c&#xF3;digo que se utiliza para inicializar campos <em>static</em>. En otras palabras, es un inicializador simple marcado con la palabra clave <em>static</em>:</p>
<pre><code class="language-java">private static String foro;
static {
    foro = &quot;Java&quot;;
}
</code></pre>
<h2 id="span-name8-orden-de-inicializacionspan-8-orden-de-inicializaci%C3%B3n"><span name="8-orden-de-inicializacion"></span> <a href="#8-orden-de-inicializacion">8.</a> Orden de Inicializaci&#xF3;n</h2>
<p>Cuando escribimos c&#xF3;digo que inicializa diferentes tipos de campos, debemos tener en cuenta el orden de inicializaci&#xF3;n.</p>
<p>En Java, el orden de las declaraciones de inicializaci&#xF3;n es el siguiente:</p>
<ol>
<li>Variables est&#xE1;ticas e inicializadores est&#xE1;ticos en orden.</li>
<li>Variables de instancia e inicializadores de instancia en orden.</li>
<li>Constructores</li>
</ol>
<h2 id="span-name9-ciclo-de-vida-del-objetospan-9-ciclo-de-vida-del-objeto"><span name="9-ciclo-de-vida-del-objeto"></span> <a href="#9-ciclo-de-vida-del-objeto">9.</a> Ciclo de Vida del Objeto</h2>
<p>Ahora que hemos aprendido c&#xF3;mo declarar e inicializar objetos, descubramos qu&#xE9; sucede con los objetos cuando no se utilizan.</p>
<p>A diferencia de otros lenguajes donde debemos preocuparnos por la destrucci&#xF3;n de objetos, Java se encarga de los objetos obsoletos a trav&#xE9;s de su recolector de basura.</p>
<p><strong>Todos los objetos en Java se almacenan en la memoria de la aplicaci&#xF3;n.</strong> De hecho, el mont&#xF3;n representa un gran conjunto de memoria no utilizada asignada para nuestra aplicaci&#xF3;n Java.</p>
<p>Por otro lado, <strong>el &apos;recolector de basura&apos; (garbage collector) es un programa Java que se encarga de la gesti&#xF3;n autom&#xE1;tica de la memoria</strong> eliminando objetos que ya no son accesibles.</p>
<p>Para que un objeto Java se vuelva inaccesible, debe encontrarse en una de las siguientes situaciones:</p>
<ul>
<li>El objeto ya no tiene referencias que lo apunten.</li>
<li>Todas las referencias que apuntan al objeto est&#xE1;n fuera de alcance.</li>
</ul>
<p>En conclusi&#xF3;n, un objeto primero se crea a partir de una clase, generalmente utilizando la palabra clave <em>new</em>. Luego, el objeto vive su vida y nos proporciona acceso a sus m&#xE9;todos y campos.</p>
<p>Finalmente, cuando ya no es necesario, el recolector de basura lo destruye.</p>
<h2 id="span-name10-otros-metodos-para-crear-objetosspan-10-otros-m%C3%A9todos-para-crear-objetos"><span name="10-otros-metodos-para-crear-objetos"></span> <a href="#10-otros-metodos-para-crear-objetos">10.</a> Otros M&#xE9;todos para Crear Objetos</h2>
<p>En esta secci&#xF3;n, echaremos un breve vistazo a <strong>m&#xE9;todos distintos de la palabra clave <em>new</em> para crear objetos, y aprenderemos c&#xF3;mo aplicarlos, espec&#xED;ficamente reflexi&#xF3;n, clonaci&#xF3;n y serializaci&#xF3;n.</strong></p>
<p><strong>La reflexi&#xF3;n es un mecanismo que podemos utilizar para inspeccionar clases, campos y m&#xE9;todos en tiempo de ejecuci&#xF3;n</strong>. Aqu&#xED; tienes un ejemplo de c&#xF3;mo crear nuestro objeto <code>Usuario</code> utilizando reflexi&#xF3;n:</p>
<pre><code class="language-java">@Test
public void cuandoSeInicializaConReflexion_entoncesLaInstanciaNoEsNula() 
  throws Exception {
    Usuario usuario = Usuario.class.getConstructor(String.class, int.class)
      .newInstance(&quot;Alicia&quot;, 2);
 
    assertThat(usuario).isNotNull();
}
</code></pre>
<p>En este caso, estamos utilizando la reflexi&#xF3;n para encontrar e invocar un constructor de la clase <code>Usuario</code>.</p>
<p>El siguiente m&#xE9;todo, <strong>la clonaci&#xF3;n, es una forma de crear una copia exacta de un objeto</strong>. Para ello, nuestra clase <code>Usuario</code> debe implementar la interfaz <code>Cloneable</code>:</p>
<pre><code class="language-java">public class Usuario implements Cloneable { //... }
</code></pre>
<p>Ahora podemos usar el m&#xE9;todo <code>clone()</code> para crear un nuevo objeto clonado <code>usuarioClonado</code> que tenga los mismos valores de propiedad que el objeto <code>usuario</code>:</p>
<pre><code class="language-java">@Test
public void cuandoSeCopiaConClonaci&#xF3;n_entoncesSeCreaUnaCoincidenciaExacta() 
  throws CloneNotSupportedException {
    Usuario usuario = new Usuario(&quot;Alicia&quot;, 3);
    Usuario usuarioClonado = (Usuario) usuario.clone();
 
    assertThat(usuarioClonado).isEqualTo(usuario);
}
</code></pre>
<p>Tambi&#xE9;n podemos utilizar la clase <code>sun.misc.Unsafe</code> para asignar memoria a un objeto sin llamar a un constructor:</p>
<pre><code class="language-java">Usuario u = (Usuario) unsafeInstance.allocateInstance(Usuario.class);
</code></pre>
<h2 id="span-name11-conclusionspan-11-conclusi%C3%B3n"><span name="11-conclusion"></span> <a href="#11-conclusion">11.</a> Conclusi&#xF3;n</h2>
<p>En este art&#xED;culo, cubrimos la inicializaci&#xF3;n de campos en Java. Luego examinamos diferentes tipos de datos en Java y c&#xF3;mo usarlos. Tambi&#xE9;n exploramos varias formas de crear objetos en Java.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>