<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Elías Canales</title>
    <description>The latest articles on Forem by Elías Canales (@elias404).</description>
    <link>https://forem.com/elias404</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3385702%2F6f271a2f-a33d-4273-b098-cf00eca30f46.jpg</url>
      <title>Forem: Elías Canales</title>
      <link>https://forem.com/elias404</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/elias404"/>
    <language>en</language>
    <item>
      <title>Tipos genéricos</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Tue, 02 Sep 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/tipos-genericos-2ma7</link>
      <guid>https://forem.com/elias404/tipos-genericos-2ma7</guid>
      <description>&lt;p&gt;Los tipos genéricos son aquellas interfaces o clases qque tienen uno o más parámetros de tipo. Los parámetros de tipo van entre el signo mayor que y el signo menor que (&amp;lt;&amp;gt;).&lt;/p&gt;

&lt;p&gt;Antes de que existieran para objetos como las listas tenías que castear cada objeto, ahora mismo eso no es necesario, siempre y cuando no uses tipos raw.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Definiendo el tipo de la lista&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1234"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//Usando RAW types&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1234"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;l2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getFirst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usar tipos raw no es recomendado, principalmente porque no podrás tener ayuda del compilador, y los errores te ocurrirán en tiempo de ejecución, los cuales son más complejos de solucionar.&lt;/p&gt;

&lt;p&gt;Y por otro lado, en los tipos raw siempre tendrás que castear, lo cual puede llevar a algún error de ejecución, además recibirás algunas advertencias que no son agradables y que son precisamente porque podrías tener errores.&lt;/p&gt;

&lt;p&gt;Lo mejor es saber qué estamos haciendo y a ser posible no tener ningún warning (typesafe), es la única manera de asegurar que todo funcionará como nosotros esperamos, o acercarnos lo máximo posible.&lt;/p&gt;

&lt;p&gt;En caso de necesitar guardar distintos tipos en una misma lista, tienes varias opciones, una podría ser guardar tener una lista de Object, no es la opción más óptima, y como normalmente a esa lista querrás aplicarle alguna operación es probable que quieras usar un tipo por medio de una interfaz.&lt;/p&gt;

&lt;p&gt;Cuando definimos una lista como hemos dicho, lo mejor es tener un tipo, de esa forma en la definición no tendremos warnings, si no sabemos el tipo o podrían ser varios, y solo vamos a hacer operaciones de lectura podemos usar “?”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//RAW type&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//Specific type&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;noWarning&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//Only to read without warning&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Al crear la lista, tenemos que decirle el tipo, aunque la mejor opción actualmente es inducirlo con tan solo poner “&amp;lt;&amp;gt;”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Raw type warning on creation&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;warning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;//Infer type&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;noWarning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, Effective Java (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Clases anidadas mejor estáticas</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Mon, 01 Sep 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/clases-anidadas-mejor-estaticas-dd6</link>
      <guid>https://forem.com/elias404/clases-anidadas-mejor-estaticas-dd6</guid>
      <description>&lt;p&gt;Para clases anidadas tenemos varios tipos, clases anidadas estaticas, clases miembro, clases locales y clases anónimas. Es importante conocer las opciones antes de decidir cuál encaja mejor y por qué.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clases anidadas (nested classes)
&lt;/h3&gt;

&lt;p&gt;Las clases anidadas son simplemente clases definidas dentro de otra clase, es algo que puede parecer raro pero tiene sentido en determinados casos. Por ejemplo, si quieres definir un Enum que solo pertenece a una clase, puedes definirlo internamente en una clase y acceder a él de la forma ClaseExterna.NombreEnum.Valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;SUPPLIER&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;CUSTOMER&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//La usariamos así&lt;/span&gt;
&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Rol&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CUSTOMER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos hacer la clase pública o privada. En el caso de un enum, esto depende principalmente de si necesitamos usar la clase externamente o no.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clases miembro (member classes)
&lt;/h3&gt;

&lt;p&gt;Las clases miembro son iguales a las clases anidadas estáticas, pero con la única diferencia de que no son estáticas. Tienen una referencia a la clase que las contiene y son creadas teniendo una instancia de su contenedor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//Instanciación peculiar&lt;/span&gt;
&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Rol&lt;/span&gt; &lt;span class="n"&gt;rol&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clases locales (local classes)
&lt;/h3&gt;

&lt;p&gt;Las clases locales son aquellas que se definen en un ambito local como un método. Tienen alcance solo donde son definidas. Es importante destacar que, si las definimos como no estáticas, pueden tener acceso a la instancia padre, mientras que si son estáticas, solo tendrán acceso a los atributos estáticos de la clase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt; &lt;span class="n"&gt;rol&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Rol&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Clases anonimas (anonymous classes)
&lt;/h3&gt;

&lt;p&gt;Son las clases más limitadas y se han utilizado comúnmente como “función”, por ejemplo, si querías tener una clase Runnable sin necesidad de crear una clase que implementase dicha interfaz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;//Clase anonima&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pero con la entrada de las funciones lambda en Java 8, ahora podemos simplemente hacer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

&lt;span class="o"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Es mucho más limpio y se entiende mejor al leer el código.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clases anidadas estáticas (static nested classes)
&lt;/h3&gt;

&lt;p&gt;Solo las clases anidadas pueden tener el modificador de comportamiento static, las clases normales no pueden. Si hacemos una clase miembro estática, tendremos una clase anidada estática.&lt;/p&gt;

&lt;p&gt;Puede ser instanciada de una forma más simple y será prácticamente lo mismo, con la diferencia de que esta no tiene una referencia a una instancia que la envuelva, porque es independiente.&lt;br&gt;
Normalmente, este tipo de clases no suelen requerir esa vinculación, y al hacerlas estáticas, estás mejorando el rendimiento y el funcionamiento del recolector de basura de Java.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, Effective Java (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Herencia vs clases etiquetadas</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Fri, 29 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/herencia-vs-clases-etiquetadas-2dil</link>
      <guid>https://forem.com/elias404/herencia-vs-clases-etiquetadas-2dil</guid>
      <description>&lt;p&gt;No suele ser muy habitual, pero a veces se crean clases que se basan en un enumerador para tomar decisiones en sus distintos métodos. Esto puede ser señal de clases etiquetadas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clases etiquetadas
&lt;/h3&gt;

&lt;p&gt;Las clases etiquetadas ocurren cuando hacemos en una clase la distinción de un tipo mediante un atributo. No confundir con el estado de una clase, aunque incluso ese enfoque también podría mejorarse con clases, pero eso es una historia diferente.&lt;/p&gt;

&lt;p&gt;Por ejemplo, si tenemos una clase que puede estar ejecutada, no ejecutada o en error, y obviamente sus métodos pueden actuar de distinta forma según el estado, esto sería parte del estado de la clase.&lt;/p&gt;

&lt;p&gt;Sin embargo, si tenemos una clase usuario y que dentro tipo un atributo rol con los valores administrador, empleado y comprador. Es probable que estemos ante un caso de clases etiquetadas, más aún cuando no todos los atributos le pertenecen a todos los tipos de usuario.&lt;/p&gt;

&lt;p&gt;Muy probablemente, en función de este tipo, tendremos un comportamiento distinto en los métodos o incluso en el constructor switch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Herencia
&lt;/h3&gt;

&lt;p&gt;La herencia consiste en otorgar más funcionalidad a una clase, al heredar de una clase superior. La clase hija hereda la funcionalidad de la clase padre y modifica o implementa su propia funcionalidad.&lt;/p&gt;

&lt;p&gt;Tomando el ejemplo anterior, supongamos que no hay usuarios que no sean administrador, empleado o comprador. En ese caso, podríamos tener una clase usuario de tipo abstracta y 3 clases que heredan de usuario.&lt;/p&gt;

&lt;p&gt;Una jerarquía de clases donde los métodos específicos están implementados en cada una de las clases, donde fuera de esto podemos hacer distinción por el tipo de la clase e incluso podemos usar sobrecarga de métodos con los tipos en otros servicios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusión
&lt;/h3&gt;

&lt;p&gt;No caigas en la trampa de crear clases etiquetadas, aunque la herencia puede traer problemas, en los casos en los cuales encaja perfectamente como una de jerarquía de clases, la herencia es la mejor solución con diferencia.&lt;br&gt;
Permitirá que tu clase sea más fácil de mantener y con un código más limpio.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>No uses interfaces para constantes</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Thu, 28 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/no-uses-interfaces-para-constantes-non</link>
      <guid>https://forem.com/elias404/no-uses-interfaces-para-constantes-non</guid>
      <description>&lt;p&gt;El llamado como “&lt;em&gt;constant interface pattern&lt;/em&gt;” es un antipatrón, que consiste en usar una interfaz de Java solo para definir constantes.&lt;br&gt;
Esta forma de usar la interfaz va en contra del propio propósito original.&lt;/p&gt;

&lt;p&gt;Desde mi punto de vista, se ha usado a veces la interfaz para definir constantes porque es una forma muy sencilla de tener un lugar donde centralizarlas, y además no puede ser instanciada.&lt;/p&gt;

&lt;p&gt;Sin embargo, no es correcto hacerlo, porque el objetivo de las interfaces es definir tipos y, al usarla solo para definir constantes, no estas definiendo ningún tipo.&lt;br&gt;
Además, alguien podría implementar esa interfaz, lo que podría generar problemas innecesarios en el futuro.&lt;/p&gt;

&lt;p&gt;Puedes crear una clase no instanciable, que actuaría como &lt;a href="https://dev.to/elias404/clases-de-utilidad-1ac4"&gt;una clase de utilidad&lt;/a&gt;, donde definir las constantes.&lt;/p&gt;

&lt;p&gt;Pero antes de hacer eso, piensa lo siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Si las constantes pertenecen a un grupo, podrías crear una enumeración (enum)&lt;/li&gt;
&lt;li&gt;Si las constantes están muy ligadas a una clase concreta, es mejor definirlas en esa clase&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Si ninguna de las opciones anteriores satisface tus necesidades, opta por una clase no instanciable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
      <category>patrones</category>
    </item>
    <item>
      <title>Cuando usar Abstract o Interface</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Wed, 27 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/cuando-usar-abstract-o-interface-4g3j</link>
      <guid>https://forem.com/elias404/cuando-usar-abstract-o-interface-4g3j</guid>
      <description>&lt;p&gt;Java ofrece mucha versatilidad para hacer las cosas de distinta forma. Antes de Java 8 había una gran diferencia entre una clase abstracta y una interfaz. Pero lo cierto es que ahora, la diferencia es más bien pequeña.&lt;/p&gt;

&lt;p&gt;Esto es debido principalmente a la definición de métodos por defecto de las interfaces. Antes de la versión 8 las interfaces solo tenían el contrato, pero no definían ninguna función por defecto. Por eso la diferencia era mucho mayor, ya que las clases abstractas pueden tanto definir contratos como implementaciones.&lt;/p&gt;

&lt;p&gt;Y aunque las cosas se pueden hacer de distinta forma, a largo plazo, no hay tantas formas que garanticen mantener nuestro código limpio y fácilmente extensible. Por eso, es interesante tener en mente un enfoque a largo plazo pero sin tampoco obsesionarnos, porque los excesos tampoco son buenos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Abstract class
&lt;/h3&gt;

&lt;p&gt;Las clases abstractas son clases que no pueden instanciarse, las cuales están hechas para ser heredadas y donde las subclases deben definir los métodos del contrato a menos que la clase que herede también sea una clase abstracta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interface
&lt;/h3&gt;

&lt;p&gt;Las interfaces son contratos, las clases pueden implementar muchos contratos, por lo que las clases pueden adquirir tipos por medio de las interfaces y hacer algo así como herencia múltiple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interfaz vs Abstract class
&lt;/h3&gt;

&lt;p&gt;Como ya comentamos en el artículo sobre “&lt;a href="https://dev.to/elias404/favorece-composicion-sobre-herencia-11ie"&gt;favorecer la composición&lt;/a&gt;”, la herencia es peligrosa siempre que no se utiliza con mucho detenimiento. Por eso, las interfaces son mucho mas interesantes a la hora de definir tipos, nos pueden permitir guardar en un listado, elementos de un mismo tipo, o lo que es lo mismo, de una misma interfaz.&lt;/p&gt;

&lt;p&gt;Pero tenemos que tener en cuenta, que las interfaces definen todos sus métodos como public por defecto (también permiten private pero solo son accesibles en esa interfaz), no podemos hacer métodos ocultos solo para el paquete o los que lo implementan (protected). Y tampoco podemos sobrescribir métodos estándar del objeto como equals, hashcode…&lt;/p&gt;

&lt;p&gt;Las interfaces pueden heredar de otras interfaces, es más, pueden heredar de más de una. Con lo cual podemos juntar tipos para crear nuevos tipos más complejos, sin perder la versatilidad de tener tipos más pequeños.&lt;/p&gt;

&lt;p&gt;Entonces, ¿Cuándo son interesantes las interfaces frente a las clases abstractas?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cuando necesitamos que una clase implemente múltiples tipos&lt;/li&gt;
&lt;li&gt;Cuando la funcionalidad no se ajusta a una jerarquía claramente definida, y se requiere un enfoque más flexible basado en contratos&lt;/li&gt;
&lt;li&gt;Cuando no necesitas una implementación común&lt;/li&gt;
&lt;li&gt;Cuando no necesitas un control detallado sobre la implementación de los métodos&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Favorece composición sobre herencia</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Tue, 26 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/favorece-composicion-sobre-herencia-11ie</link>
      <guid>https://forem.com/elias404/favorece-composicion-sobre-herencia-11ie</guid>
      <description>&lt;p&gt;Cuando queremos crear una clase reutilizando la funcionalidad de otra clase, podemos pensar en usar herencia. Pero, ¿Es esta la mejor solución?&lt;/p&gt;

&lt;h3&gt;
  
  
  Herencia
&lt;/h3&gt;

&lt;p&gt;En Java solo podemos extender de una clase, al extender tendremos la funcionalidad extra de todas las superclases, ya que, aunque solo podemos heredar de una clase, esa clase a su vez puede heredar de otra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Automobile&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getBrand&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Automobile&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Car&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getSeats&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sports&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Sports&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brand&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getBrand&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La clase Sport hereda de Car y la de Car de Automobile. En este caso que las propiedades son privadas no podemos acceder directamente, pero sí que podemos alterar el método getBrand().&lt;/p&gt;

&lt;p&gt;Aunque solo tendremos acceso a los atributos y funciones que no tengan el modificador de acceso private. Para la herencia es interesante el modificador de acceso protected, ya que permite acceder desde la clase que hereda, incluso si está en otro paquete.&lt;/p&gt;

&lt;p&gt;La herencia rompe la encapsulación, podemos alterar el objetivo real del objeto. Al sobrescribir métodos, y dependiendo de cómo se haya diseñado el objeto, podemos alterar el funcionamiento original de la clase.&lt;/p&gt;

&lt;p&gt;Por eso, tenemos que hacer la pregunta de si realmente necesitamos que se herede uno de los objetos fuera del paquete, pero también si es necesario que hereden de ese objeto, si realmente existe una relación de herencia entre ambos objetos (subclase y superclase)..&lt;/p&gt;

&lt;h3&gt;
  
  
  Encapsulación
&lt;/h3&gt;

&lt;p&gt;Consiste en no permitir el acceso a propiedades, métodos o clases, utilizando los modificadores de acceso (private, default, protected y public). Con esto podemos prevenir el mal uso de nuestras clases, forzando a permitir acceder a aquello estrictamente necesario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Composición
&lt;/h3&gt;

&lt;p&gt;La composición es una forma de darle funcionalidad a nuestra clase, pero no sobrescribimos los métodos de la clase original. Estamos creando una nueva clase.&lt;br&gt;
En programación se traduce básicamente en tener un atributo, si en lugar de heredar tenemos esa clase como atributo.&lt;/p&gt;

&lt;p&gt;Veamos que pasaría si tenemos una clase que hereda de ArrayList, creamos la clase CarList, nosotros queremos tener un conteo de las marcas de los coches cuando se añade un nuevo coche a la CarList.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CarList&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Car&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;carBrandCount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addCar&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//count car brands&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A priori no hay ningún problema, tenemos nuestra CarList, donde contamos las marcas y así pues luego no tenemos que contar cada vez que nos lo pidan. Pero si tu instancias el CarList verás métodos que no tienen ningún sentido:&lt;/p&gt;

&lt;p&gt;Tenemos el addCar que creamos nosotros, pero también tenemos addAll, add, stream…&lt;/p&gt;

&lt;p&gt;Como dijimos antes, la herencia rompe la encapsulación, ahora pueden manipular el estado interno de nuestro objeto (la lista de los coches), con métodos que nosotros no queremos exponer o que romperían el correcto funcionamiento.&lt;/p&gt;

&lt;p&gt;Una solución a este problema es la composición, si tenemos la lista como atributo de la clase, podemos exponer los métodos que nos interesen, y controlar el funcionamiento de nuestra CarList, y por supuesto, no utilizar la herencia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Minimiza los objetos mutables</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Mon, 25 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/minimiza-los-objetos-mutables-1kij</link>
      <guid>https://forem.com/elias404/minimiza-los-objetos-mutables-1kij</guid>
      <description>&lt;p&gt;Los objetos inmutables son aquellos que no pueden cambiar su estado una vez creados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;passport&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;school&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;UserManual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;passport&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;school&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;passport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;passport&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;school&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;school&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;También se puede conseguir con los record de Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;UserRecord&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;passport&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                         &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                         &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;school&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En principio, haciendo los atributos private final y ofreciendo métodos de acceso, estos objetos permanecerán inmutables. Aunque tenemos que tener en cuenta que si pasamos otro objeto, ese sí que podría no ser inmutable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Immutable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;//Alteramos el estado interno&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Immutable&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Immutable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;());&lt;/span&gt;
&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y al igual que con una lista podemos hacer lo mismo con otros objetos que no sean inmutables. Una solución es que la gestionemos nosotros, o hacer una copia defensiva y convertirla en una lista no modificable.&lt;/p&gt;

&lt;p&gt;No obstante, a veces sí es necesario que parte sea modificable o que pueda tener ciertas operaciones. Aunque lo mejor es que todo sea inmutable, porque te ayuda a entender mejor el código, ya que sabes que los objetos que ves no cambian de estado por el camino.&lt;/p&gt;

&lt;p&gt;Por ejemplo, una llamada a una función podría alterar el estado de un objeto y no ser visible en la función principal. Además, los objetos inmutables son thread-safe por esa misma razón.&lt;/p&gt;

&lt;p&gt;Que los objetos sean inmutables nos hace pensar de otra manera, y es que programar con objetos inmutables es una programación funcional, donde para poder tener un nuevo estado acabamos creando un nuevo objeto.&lt;br&gt;
Mientras que en la programación imperativa se cambia el estado de los objetos.&lt;/p&gt;

&lt;p&gt;Para hacer objetos inmutables, necesitas que no puedan heredarse, porque al heredar se podría sobrescribir su comportamiento.&lt;br&gt;
Hay dos estrategias para hacer eso, una es haciendo la clase final y la otra con constructor privado y factoría estática (lo explico con más detalle en el patrón &lt;a href="https://dev.to/elias404/singleton-5g7l"&gt;Singleton&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Los objetos inmutables deberían cumplir las siguientes propiedades:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No tener métodos que permitan modificar propiedades&lt;/li&gt;
&lt;li&gt;No permitir que la clase pueda heredarse&lt;/li&gt;
&lt;li&gt;Que todas las propiedades sean final&lt;/li&gt;
&lt;li&gt;Que todas las propiedades sean private&lt;/li&gt;
&lt;li&gt;En caso de tener propiedades que sean objetos, no deberíamos confiar en el cliente y hacer copias defensivas.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>No utilices atributos públicos</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Fri, 22 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/no-utilices-atributos-publicos-44bf</link>
      <guid>https://forem.com/elias404/no-utilices-atributos-publicos-44bf</guid>
      <description>&lt;p&gt;Cuando estes definiendo tu código, piensa que cuanto menos acceso se tenga a tus clases, métodos o atributos, más fácil será hacer modificaciones y menos partes de tu código se verán afectadas.&lt;/p&gt;

&lt;p&gt;De ahí nace la idea de no dejar tus atributos como públicos. Aunque siempre hay excepciones. Más adelante hablaremos de esas excepciones, ahora centrémonos en las ventajas de no hacerlo público, y seguramente alguna vez te has preguntado qué sentido tiene tener getter y setter (llenando tus clases de métodos ‘vacios’).&lt;/p&gt;

&lt;p&gt;Lo cierto es que, la mayoría de las veces, eso no tiene ningún sentido, porque esos métodos no aportan gran cosa.&lt;br&gt;
Tenemos la suerte de que pueden ser generados por librerías como Lombok.&lt;/p&gt;

&lt;p&gt;Pero la idea de esos métodos nace principalmente de que podemos hacer acciones, tanto al obtener como al establecer valor.&lt;/p&gt;

&lt;p&gt;Aunque no sea lo ideal, imagina que una de tus clases es muy utilizada a través de sus métodos setter y getter.&lt;br&gt;
En uno de los desarrollos te has dado cuenta que necesitas cambiar el tipo. Quieres cambiarlo para todo el código porque encuentras que a largo plazo es una muy buena solución.&lt;/p&gt;

&lt;p&gt;Si el atributo es público, tendrás que cambiar todos los lugares donde se usa. En cambio, si accedes mediante métodos, puedes usar sobrecarga para seguir devolviendo o estableciendo el valor como antes, sin tocar el código cliente, modificando solo tu clase.&lt;/p&gt;

&lt;p&gt;Como te dije antes hay excepciones, la excepción es cuando la clase tiene acceso de paquete privado. Es decir, a una clase podemos ponerle el modificador de acceso public o dejarla sin modificador de acceso.&lt;/p&gt;

&lt;p&gt;Cuando la dejamos sin modificador, entonces tenemos una clase de acceso privado que solo es accesible en ese paquete (por supuesto, también podemos tener clases anidadas en ese caso esto también aplica).&lt;br&gt;
Cuando la clase es de acceso privado, somos nosotros los que controlamos en un pequeño espacio (el paquete), quien y cómo la utiliza, y por tanto, podemos usar el acceso público.&lt;/p&gt;

&lt;p&gt;En principio para las clases inmutables, deberíamos hacer lo mismo que con las clases mutables, para poder beneficiarnos de las mismas ventajas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Implementando Comparable</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Thu, 21 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/implementando-comparable-1clh</link>
      <guid>https://forem.com/elias404/implementando-comparable-1clh</guid>
      <description>&lt;p&gt;La interfaz &lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Comparable.html" rel="noopener noreferrer"&gt;Comparable&lt;/a&gt; no solo permite saber si dos objetos son iguales, además, podemos saber cual es menor o mayor. Esta interfaz debe ser implementada explícitamente, a diferencia de equals() que se hereda de Object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;otro&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Con esta interfaz habilitamos el uso de funciones que necesitan de objetos comparables. Por ejemplo, los algoritmos de ordenación necesitan poder comparar objetos y saber si es igual, mayor o menor.&lt;/p&gt;

&lt;p&gt;También hay clases que para poder funcionar deben de poder comparar objetos, por ejemplo, TreeSet. Si construyes un TreeSet con objetos que no implementan la interfaz Comparable, veras que te dará una advertencia, básicamente porque no va a funcionar correctamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TreeSet&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparingInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;User:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque también esta la opción de pasar una función de comparación, pero tienes que tener en cuenta que si en otro punto del código, vas a volver a necesitarlo, lo mejor sería implementarla directamente en el objeto.&lt;/p&gt;

&lt;p&gt;El contrato de esta interfaz debería &lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Comparable.html#compareTo(T)" rel="noopener noreferrer"&gt;cumplir&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tener simetría:&lt;/strong&gt; Tenemos un objeto X y uno Y, si hacemos &lt;code&gt;X.compareTo(Y)&lt;/code&gt; y obtenemos un mayor a 0. Cuando hagamos un &lt;code&gt;Y.compareTo(X)&lt;/code&gt; tenemos que obtener un número negativo. Esto asegura que si X es mayor que Y, entonces Y sera menor que X. (Relativo a esto si &lt;code&gt;X.compareTo(Y)&lt;/code&gt; da excepción, &lt;code&gt;Y.compareTo(X)&lt;/code&gt; también debería dar excepción).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Propiedad transitiva:&lt;/strong&gt; Si tenemos que &lt;code&gt;X &amp;gt; Y &amp;gt; Z&lt;/code&gt; entonces &lt;code&gt;X &amp;gt; Z&lt;/code&gt;. Por lo que, &lt;code&gt;X.compareTo(Y) &amp;gt; 0&lt;/code&gt;, y &lt;code&gt;Y.compareTo(Z) &amp;gt; 0&lt;/code&gt;, entonces &lt;code&gt;X.compareTo(Z) &amp;gt; 0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Por último, si dos objetos son iguales &lt;code&gt;X.compareTo(Y) == 0&lt;/code&gt;. Entonces, el resultado contra un tercer objeto de X y Y debe ser igual. &lt;code&gt;signo(X.compareTo(Z)) == signo(Y.compareTo(Z))&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Es recomendable que si dos objetos son iguales para el equals() que también lo sean para el compareTo &lt;code&gt;(X.compareTo(Y) == Y.compareTo(X))&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cuando pongo que es mayor/menor a 0 o que se mira el signo(), es porque el compareTo no va a devolver 0, 1 y -1. Va a devolver 0, mayor a 0 o menor a 0.&lt;/p&gt;

&lt;p&gt;Para implementar este método iremos evaluando cada una de las propiedades más relevantes del objeto, hasta encontrar una que no sea igual, y devolveremos la respuesta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;COMPARATOR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nc"&gt;Comparator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;comparingInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Box:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenComparingDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Box:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenComparingDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Box:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenComparingDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;Box:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;compareTo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Box&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;COMPARATOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compare&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A la hora de comparar es mejor utilizar los métodos estáticos de los tipos para comparar que usar '&amp;lt;' y '&amp;gt;'.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Comparable.html#compareTo(T)" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Comparable.html#compareTo(T)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Siempre sobrescribe toString()</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Wed, 20 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/siempre-sobrescribe-tostring-1po7</link>
      <guid>https://forem.com/elias404/siempre-sobrescribe-tostring-1po7</guid>
      <description>&lt;p&gt;Salvo que estes usando una clase de tipo &lt;em&gt;record&lt;/em&gt;, necesitaras sobrescribir el toString() para que tenga sentido cuando estes debugeando o un test te falle y lo que veas en pantalla sea:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected :User@6c3f5566
Actual :User@12405818
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La utilidad es 0, obviamente siempre que puedas utilizar clases inmutables record sera mucho mejor, pero si necesitas crear clases, en ese caso sobrescribe directamente el toString().&lt;/p&gt;

&lt;p&gt;Lo normal es que todos los atributos del equals() esten en el toString(), el único caso en el cual, algún atributo podría no estar completo en el toString(), es cuando quieres enmascarar o ocultar, algún dato. Pero en ese caso también habría que valorar si tiene sentido tener ese dato y de esa forma en el equals().&lt;/p&gt;

&lt;p&gt;Los atributos que salen en el equals() deberían ser accesibles por los desarrolladores, porque si quisieran sobrescribir el toString() o mostrarlo de otra forma tendrían que extraer la información del toString() lo que es propenso a cometer errores.&lt;/p&gt;

&lt;p&gt;Este método puedes generarlo de forma automática, por ejemplo, usando &lt;a href="https://projectlombok.org/features/ToString" rel="noopener noreferrer"&gt;Lombok&lt;/a&gt;, o bien usando &lt;a href="https://commons.apache.org/proper/commons-lang//apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html" rel="noopener noreferrer"&gt;ReflectionToStringBuilder&lt;/a&gt; ambos te permiten excluir atributos.&lt;/p&gt;

&lt;p&gt;Si quisieras enmascarar atributos, creo que la mejor opción es crear una clase especifica para ese atributo y sobrescribir su toString().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Prueba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Account&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="nf"&gt;Account&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://commons.apache.org/proper/commons-lang//apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html" rel="noopener noreferrer"&gt;https://commons.apache.org/proper/commons-lang//apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://projectlombok.org/features/ToString" rel="noopener noreferrer"&gt;https://projectlombok.org/features/ToString&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
    </item>
    <item>
      <title>Sobrescribiendo hashCode()</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Tue, 19 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/sobrescribiendo-hashcode-47j9</link>
      <guid>https://forem.com/elias404/sobrescribiendo-hashcode-47j9</guid>
      <description>&lt;p&gt;El método hashCode, es heredado de Object, normalmente de forma indirecta, y su utilidad principal es devolver un entero que representa al objeto.&lt;/p&gt;

&lt;p&gt;Siempre que sobrescribes el método equals deberas sobrescribir el método hashCode para cumplir con el &lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Object.html#hashCode()" rel="noopener noreferrer"&gt;contrato&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Concretamente por la segunda regla: “&lt;em&gt;If two objects are equal according to the equals method, then calling the hashcode method on each of the two objects must produce the same integer result&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;Como Java en principio devuelve un número de la referencia del objeto (como hashCode), si sobrescribes equals y tienes dos objetos iguales, su hashcode sera distinto, y por tanto, no estarás cumpliendo el contrato.&lt;/p&gt;

&lt;h3&gt;
  
  
  El hashCode debe
&lt;/h3&gt;

&lt;p&gt;Durante una misma ejecución de programa, para objeto de un determinado equals siempre debe devolver el mismo hashCode. Pero para otra ejecución este valor no es necesario que sea el mismo.&lt;/p&gt;

&lt;p&gt;Dos instancias distintas, pero que el equals es igual, deben devolver el mismo hashCode&lt;/p&gt;

&lt;p&gt;Si dos objetos son distintos, el hashCode() no tiene porque ser distinto pero si para objetos distintos, el hashCode es distinto eso mejorara el número de colisiones, y por tanto, el rendimiento de las tablas hash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Como lo implementamos
&lt;/h3&gt;

&lt;p&gt;Tenemos que usar los atributos relevantes, que son los mismos que usamos en el equals para que dos objetos iguales tengan el mismo hashCode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Si el dato relevante es primitivo, aplicaremos TipoPrimitivo.hashCode()&lt;/li&gt;
&lt;li&gt;Si el dato relevante es complejo, y en el equals lo hemos hecho llamando recursivamente al equals del objeto, en este caso haremos lo mismo&lt;/li&gt;
&lt;li&gt;Si necesitas hacer una validación más compleja, entonces crea una representación del objeto con un tipo primitivo y llama al hashCode como en el punto 2.&lt;/li&gt;
&lt;li&gt;Si es nulo devuelve 0.&lt;/li&gt;
&lt;li&gt;Si es un array y tiene un elemento significativo usa ese como hashCode, si no tiene ninguno usa una constante que no sea 0, y si todos son relevantes usa Arrays.hashCode().&lt;/li&gt;
&lt;li&gt;Para combinar los distintos atributos, utiliza:
hashCode = 31 * hashCode + &lt;/li&gt;
&lt;li&gt;Finalmente devuelve el hashCode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Creo que lo más peculiar es el 31, básicamente ese número se utiliza para reducir el número de colisiones. Dado que dos objetos distintos podrían tener el mismo hashCode, el objetivo es reducir las colisiones.&lt;/p&gt;

&lt;p&gt;Además, los compiladores son capaces de optimizar mucho esa multiplicación.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lombok
&lt;/h3&gt;

&lt;p&gt;Podemos generar el equals y hashCode usando la anotación &lt;code&gt;[@EqualsAndHashCode](https://projectlombok.org/features/EqualsAndHashCode)&lt;/code&gt; de lombok.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://www.geeksforgeeks.org/why-does-javas-hashcode-in-string-use-31-as-a-multiplier/" rel="noopener noreferrer"&gt;https://www.geeksforgeeks.org/why-does-javas-hashcode-in-string-use-31-as-a-multiplier/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://projectlombok.org/" rel="noopener noreferrer"&gt;https://projectlombok.org/&lt;/a&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
      <category>patrones</category>
    </item>
    <item>
      <title>Método equals() en Java</title>
      <dc:creator>Elías Canales</dc:creator>
      <pubDate>Mon, 18 Aug 2025 12:00:00 +0000</pubDate>
      <link>https://forem.com/elias404/metodo-equals-en-java-5b9d</link>
      <guid>https://forem.com/elias404/metodo-equals-en-java-5b9d</guid>
      <description>&lt;p&gt;Claves para definir la igualdad lógica entre objetos&lt;/p&gt;

&lt;p&gt;Es un problema que pues encontrar fácilmente cuando programas en Java, probablemente con la clase String, y es que si quieres comparar Objetos necesitas equals() porque si usas ‘==’ lo que estás comparando es la referencia.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Valor NO tiene implementado el método equals()&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;//Valor tiene implementado el método equals()&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando no tenemos implementado el método equals() la comparación ‘==’ tiene el mismo resultado. Es decir, estamos comparando la referencia. Pero si implementamos el método equals() ya es diferente. Ya tendremos la comparación de valor y referencia, separadas.&lt;/p&gt;

&lt;p&gt;Antes de adentrarnos en cómo debe ser un método equals, podemos empezar hablando de cuando deberíamos de sobrescribir este método.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cuando la clase sea una clase valor, es decir, cuando está representando algo que por sus atributos podemos decir, si es o no igual a otro objeto.&lt;/li&gt;
&lt;li&gt;Cuando la instancia por sí misma no es única. Por ejemplo, una clase de un servicio en principio es única, si queremos saber si es la misma podemos usar ‘==’ porque no tiene propiedades que la hagan única frente a otra.&lt;/li&gt;
&lt;li&gt;Cuando la superclase no tiene un método equals(). Para evitar romper la propiedad transitiva (más adelante hablaremos de esto).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Una vez tenemos claro que queremos un método equals(), lo siguiente es empezar a sobrescribirlo haciendo uso de la anotación &lt;code&gt;@Override&lt;/code&gt;, esto es importante porque nos garantiza que realmente estamos sobrescribiendo.&lt;/p&gt;

&lt;p&gt;Ya que si no estamos sobrescribiendo nada, tendremos una alerta por parte del IDE, o en tiempo de compilación.&lt;br&gt;
Por ejemplo, si en vez de hacer equals(Object o) hacemos equals(Valor v).&lt;/p&gt;

&lt;p&gt;Claramente no estamos sobrescribiendo el método equals() y podríamos tener resultados no deseados, por ello, mejor utilizar la anotación &lt;code&gt;@Override&lt;/code&gt; en estos casos.&lt;/p&gt;

&lt;p&gt;Si vamos a la documentación sobre este método vamos a ver las propiedades que debería de tener un método &lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Object.html#equals(java.lang.Object)" rel="noopener noreferrer"&gt;equals()&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reflexiva&lt;/strong&gt;: Debe ser igual asimismo, obviamente el mismo objeto con los mismo valores debe decirnos que es igual (a.equals(a)).&lt;br&gt;
&lt;strong&gt;Simétrica&lt;/strong&gt;: No importa el orden que comparemos, es decir, debe ser lo mismo decir que ‘a’ es igual a ‘b’, que ‘b’ es igual a ‘a’ (a.equals(b) &amp;amp;&amp;amp; b.equals(a) == true).&lt;br&gt;
&lt;strong&gt;Transitiva&lt;/strong&gt;: Si tenemos 3 instancias ‘a’,’b’ y ‘c’, si sabemos que a == b y&lt;br&gt;
b == c, entonces a == c (a.equals(b) &amp;amp;&amp;amp; b.equals(c) &amp;amp;&amp;amp; a.equals(c)).&lt;br&gt;
&lt;strong&gt;Consistente&lt;/strong&gt;: Si llamamos varias veces a a.equals(b) y no hemos cambiado ninguno de los dos objetos, el resultado siempre debería ser el mismo.&lt;br&gt;
&lt;strong&gt;Comparado contra un null&lt;/strong&gt;: Devolver falso cuando se compara con un nulo (a.equals(null) == false).&lt;/p&gt;

&lt;p&gt;Como podemos ver todas las propiedades tienen lógica, no son nada raro. Pero aunque parezca que es difícil romper alguna de esas propiedades, lo cierto es que hay algunas situaciones que pueden llevarnos a romperlo.&lt;/p&gt;
&lt;h3&gt;
  
  
  Romper simetría
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(((&lt;/span&gt;&lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;num&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Una forma de romper la simetría es tratar dos tipos dentro de un equals(), de hecho es uno de los motivos para no hacer un equals(), porque si la clase que estas creando hereda de otra, y la superclase ya tiene una definición del método equals, en ese caso no lo sobrescribas.&lt;/p&gt;

&lt;p&gt;Fíjate en el ejemplo, está claro que si comparamos dos objetos Valor va a funcionar. Si comparamos un Valor con un Integer también, pero y al reves que pasaría.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Como vemos, ‘a’ sí es igual a ‘b’, pero ‘b’ no es igual a ‘a’. Es algo obvio, pero tenemos que tener cuidado de no querer cubrir dos tipos en un equals(), vamos a ver que algo muy similar que pasa para el problema transitivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Romper transitividad
&lt;/h3&gt;

&lt;p&gt;Tenemos la clase Valor en la cual implementamos el equals() solo para la clase Valor. Luego hemos creado una clase que hereda de Valor, que hemos llamado ValorAvanzado.&lt;/p&gt;

&lt;p&gt;Si no tenemos en cuenta Valor en ValorAvanzado, estaríamos rompiendo simetría, porque tenemos que tener en cuenta que un ValorAvanzado también es un Valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Valor&lt;/span&gt;
&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(((&lt;/span&gt;&lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;num&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//ValorAvanzado&lt;/span&gt;
&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ValorAvanzado&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; 
          &lt;span class="n"&gt;decimals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(((&lt;/span&gt;&lt;span class="nc"&gt;ValorAvanzado&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;decimals&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValorAvanzado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Valor&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ValorAvanzado&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque ‘a’ es igual a ‘b’, y ‘b’ es igual a ‘c’, resulta que ‘a’ no es igual a ‘c’ en este caso. Por tanto, hemos roto la simetría. Como decía antes es muy similar al anterior, y es que cuando queremos abarcar dos tipos en un equals() nos vamos a encontrar problemas.&lt;/p&gt;

&lt;p&gt;Este caso, concretamente, dado que la superclase ya tiene definido el método equals() no debemos sobrescribirlo. En caso de hacerlo tenemos que saber las consecuencias, y rompiendo alguna de las propiedades que la propia documentación establece, puede llevarnos a situaciones no deseadas.&lt;/p&gt;

&lt;p&gt;La mejor solución en este caso, es hacer uso de la composición en vez de la herencia. Con la cual, podríamos tener un método equals() funcional para ambas clases.&lt;/p&gt;

&lt;h4&gt;
  
  
  Romper consistencia
&lt;/h4&gt;

&lt;p&gt;La consistencia se puede romper por las operaciones que hagamos en el propio método equals(). Por ejemplo, si tenemos que hacer una llamada a un servicio externo, eso podría dar resultados no deterministas, y por tanto, romper la consistencia. Debemos solo hacer uso de elementos que están en memoria y nos permitirán tener resultados deterministas.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lombok
&lt;/h3&gt;

&lt;p&gt;En Lombok hay una anotación para definir automáticamente el equals y el hashCode (&lt;code&gt;@EqualsAndHashCode&lt;/code&gt;), ya que cuando se sobrescribe el equals debes sobrescribir el hashCode. Pero debes tener en cuenta que la anotación de Lombok no va a arreglar todos los problemas que hemos comentado, sobre todo los relativos a herencia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referencias&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Object.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/Object.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://projectlombok.org" rel="noopener noreferrer"&gt;https://projectlombok.org&lt;/a&gt;&lt;br&gt;
Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3ª edición), Addison-Wesley, 2018.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>effectivejava</category>
      <category>java</category>
      <category>patrones</category>
    </item>
  </channel>
</rss>
