{"id":31,"date":"2014-05-26T12:06:23","date_gmt":"2014-05-26T12:06:23","guid":{"rendered":"http:\/\/vkrastev1blog.com\/?p=31"},"modified":"2014-05-26T15:36:27","modified_gmt":"2014-05-26T15:36:27","slug":"java-generics-explained-in-short-form-with-examples","status":"publish","type":"post","link":"https:\/\/vkrastev1blog.com\/2014\/05\/26\/java-generics-explained-in-short-form-with-examples\/","title":{"rendered":"Los gen\u00e9ricos de Java explicados brevemente con ejemplos"},"content":{"rendered":"<p>Consulte estas preguntas frecuentes para obtener m\u00e1s informaci\u00f3n:<\/p>\n<p><a href=\"http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1\" rel=\"nofollow\">http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1<\/a><\/p>\n<p>Aqu\u00ed, de forma resumida, algunos puntos importantes de estas preguntas frecuentes.<\/p>\n<p>Ejemplo (de tipo gen\u00e9rico):<\/p>\n<blockquote><p><tt> clase Par&lt;X,Y&gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0 privado X primero;<\/tt><br \/>\n<tt> \u00a0 privado Y segundo;<\/tt><tt> \u00a0 Par p\u00fablico(X a1, Y a2) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 primero = a1;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 segundo = a2;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 public X getFirst() { regresar primero; }<\/tt><br \/>\n<tt> \u00a0 public Y getSecond() { devolver segundo; }<\/tt><br \/>\n<tt> \u00a0 public void setFirst(X arg) { primero = arg; }<\/tt><br \/>\n<tt> \u00a0 public void setSecond(Y arg) { segundo = arg; }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>la clase <tt> Par<\/tt> tiene dos par\u00e1metros de tipo <tt> inc\u00f3gnita <\/tt> y <tt> Y<\/tt> .\u00a0 Se reemplazan por argumentos de tipo cuando el tipo gen\u00e9rico <tt> Par<\/tt> est\u00e1 instanciado. Por ejemplo, en la declaraci\u00f3n <tt> Par&lt;Cadena, Fecha&gt;<\/tt> el par\u00e1metro de tipo <tt> inc\u00f3gnita<\/tt> se reemplaza por el argumento de tipo <tt> Cadena<\/tt> y <tt> Y<\/tt> es reemplazado por\u00a0 <tt> Fecha<\/tt> .<br \/>\nEl alcance de los identificadores. <tt> inc\u00f3gnita <\/tt> y <tt> Y<\/tt> es<b> <i> <\/i> <\/b> toda la definici\u00f3n de la clase.\u00a0 En este \u00e1mbito los dos par\u00e1metros de tipo <tt> inc\u00f3gnita <\/tt> y <tt> Y<\/tt> se utilizan como si fueran tipos (con algunas restricciones). En el ejemplo anterior, los par\u00e1metros de tipo se utilizan como argumento y tipo de retorno de los m\u00e9todos de instancia y los tipos de campos de instancia.<br \/>\nLos par\u00e1metros de tipo se pueden declarar con l\u00edmites. Los l\u00edmites dan acceso a m\u00e9todos del tipo desconocido que representa el par\u00e1metro de tipo. En nuestro ejemplo, no invocamos ning\u00fan m\u00e9todo de tipo desconocido. <tt> inc\u00f3gnita <\/tt> y <tt> Y<\/tt> . Por este motivo, los dos par\u00e1metros de tipo no est\u00e1n limitados.<\/p>\n<p>Ejemplo (de un tipo parametrizado concreto):<\/p>\n<blockquote><p><tt> par de impresi\u00f3n p\u00fablico vac\u00edo (<b> <span style=\"color:#000099;\"> Par&lt;Cadena,Largo&gt;<\/span> <\/b> par) {<\/tt><br \/>\n<tt> \u00a0 System.out.println(\"(\"+pair.getFirst()+\",\"+pair.getSecond()+\")\");<\/tt><br \/>\n<tt> }<\/tt><tt> <b> <span style=\"color:#000099;\"> Par&lt;Cadena,Largo&gt;<\/span> <\/b> l\u00edmite = nuevo <b> <span style=\"color:#000099;\"> Par&lt;Cadena,Largo&gt;<\/span> <\/b> (\"m\u00e1ximo\",1024L);<\/tt><br \/>\n<tt> imprimirPar(l\u00edmite);<\/tt><\/p><\/blockquote>\n<p>Ejemplo (de un tipo parametrizado con comod\u00edn):<\/p>\n<blockquote>\n<blockquote><p><tt> par de impresi\u00f3n p\u00fablico vac\u00edo (<b> <span style=\"color:#000099;\"> Par&lt;?,?&gt;<\/span> <\/b> par) {<\/tt><br \/>\n<tt> \u00a0 System.out.println(\"(\"+pair.getFirst()+\",\"+pair.getSecond()+\")\");<\/tt><br \/>\n<tt> }<\/tt><tt> <b> <span style=\"color:#000099;\"> Par&lt;?,?&gt;<\/span> <\/b> l\u00edmite = nuevo <b> <span style=\"color:#000099;\"> Par&lt;Cadena,Largo&gt;<\/span> <\/b> (\"m\u00e1ximo\",1024L);<\/tt><br \/>\n<tt> imprimirPar(l\u00edmite);<\/tt><\/p><\/blockquote>\n<\/blockquote>\n<p>Todas las instancias de un tipo gen\u00e9rico comparten la misma representaci\u00f3n del tipo de tiempo de ejecuci\u00f3n, es decir, la representaci\u00f3n del tipo sin formato. Por ejemplo, las instancias de un tipo gen\u00e9rico. <tt> Lista<\/tt> , como <tt> Lista&lt;Fecha&gt;<\/tt> , <tt> Lista&lt;Cadena&gt;<\/tt> , <tt> Lista&lt;Long&gt;<\/tt> , etc. tienen diferentes tipos est\u00e1ticos en el momento de la compilaci\u00f3n, pero el mismo tipo din\u00e1mico <tt> Lista <\/tt> en tiempo de ejecuci\u00f3n.<\/p>\n<p>Un elenco consta de dos partes:<\/p>\n<ul>\n<li>una verificaci\u00f3n de tipo est\u00e1tico realizada por el compilador en el momento de la compilaci\u00f3n y<\/li>\n<li>una verificaci\u00f3n de tipo din\u00e1mica realizada por la m\u00e1quina virtual en tiempo de ejecuci\u00f3n.<\/li>\n<\/ul>\n<p>La parte est\u00e1tica clasifica los lanzamientos sin sentido que no pueden tener \u00e9xito, como el lanzamiento de <tt> Cadena<\/tt> eso <tt> Fecha<\/tt> o de <tt> Lista&lt;Cadena&gt;<\/tt> eso <tt> Lista&lt;Fecha&gt;<\/tt> .<\/p>\n<p>La parte din\u00e1mica utiliza la informaci\u00f3n del tipo de tiempo de ejecuci\u00f3n y realiza una verificaci\u00f3n de tipo en tiempo de ejecuci\u00f3n.\u00a0 Se plantea un <tt> Excepci\u00f3n ClassCast<\/tt> si el tipo din\u00e1mico del objeto no es el tipo de destino (o un subtipo del tipo de destino) de la conversi\u00f3n. Ejemplos de elencos con una parte din\u00e1mica son el elenco de <tt> Objeto<\/tt> eso <tt> Cadena<\/tt> o de <tt> Objeto<\/tt> eso <tt> Lista&lt;Cadena&gt;<\/tt> .\u00a0 Estos son los llamados abatidos, desde un supertipo hasta un subtipo.<\/p>\n<p>Ejemplos de tipos parametrizados concretos son <tt> Lista&lt;Cadena&gt;<\/tt> , <tt> Mapa&lt;Cadena,Fecha&gt;<\/tt> , pero no <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> o <tt> Mapa&lt;String,?&gt;<\/tt> .<\/p>\n<p>A veces se espera que un <tt> Lista&lt;Objeto&gt;<\/tt> ser\u00eda un supertipo de <tt> Lista&lt;Cadena&gt;<\/tt> , porque <tt> Objeto<\/tt> es un supertipo de <tt> Cadena<\/tt> .\u00a0 Esta expectativa surge del hecho de que existe este tipo de relaci\u00f3n para las matrices:\u00a0 <tt> Objeto[]<\/tt> es un supertipo de <tt> Cadena[]<\/tt> , porque <tt> Objeto<\/tt> es un supertipo de <tt> Cadena<\/tt> . (Este tipo de relaci\u00f3n se conoce como <i> covarianza<\/i> .) La relaci\u00f3n de supersubtipo de los tipos de componentes se extiende a los tipos de matriz correspondientes. No existe tal relaci\u00f3n de tipos para instancias de tipos gen\u00e9ricos. (Los tipos parametrizados son <i> no<\/i> covariante.)<\/p>\n<p>La falta de una relaci\u00f3n de supersubtipo entre instancias del mismo tipo gen\u00e9rico tiene varias consecuencias.\u00a0 Aqu\u00ed hay un ejemplo.<\/p>\n<p>Ejemplo:<\/p>\n<p><tt> void printAll(ArrayList&lt;Object&gt; c) {<\/tt><br \/>\n<tt> \u00a0 para (Objeto o: c)\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 System.out.println(o);<\/tt><br \/>\n<tt> }<\/tt><tt> Lista ArrayList&lt;String&gt; = nueva ArrayList&lt;String&gt;();<\/tt><br \/>\n<tt> ... llenar lista ...<\/tt><br \/>\n<tt> imprimirTodo(lista);\u00a0\u00a0 \/\/ error<\/tt><\/p>\n<p>A <tt> ArrayList&lt;String&gt;<\/tt> El objeto no se puede pasar como argumento a un m\u00e9todo que solicita una <tt> ArrayList&lt;Object&gt;<\/tt> porque los dos tipos son instancias del mismo tipo gen\u00e9rico, pero para <i> diferente<\/i> argumentos de tipo, y por esta raz\u00f3n no son compatibles entre s\u00ed.<\/p>\n<p>Los tipos parametrizados concretos son instancias concretas de un tipo gen\u00e9rico.\u00a0 Son casi como tipos; s\u00f3lo hay unas pocas restricciones.\u00a0 NO se pueden utilizar para los siguientes fines:<\/p>\n<ul>\n<li>para la creaci\u00f3n de matrices<\/li>\n<li>en el manejo de excepciones<\/li>\n<li>en una clase literal<\/li>\n<li>en un <tt> instancia de<\/tt> expresi\u00f3n<\/li>\n<\/ul>\n<p>Las matrices que contienen elementos cuyo tipo es un tipo parametrizado concreto son ilegales.<\/p>\n<p>Ejemplo (de tipo de matriz ilegal):<\/p>\n<p><tt> prueba de vac\u00edo est\u00e1tico() {<\/tt><br \/>\n<tt> \u00a0 <b> <span style=\"color:#660000;\"> Par&lt;Entero,Entero&gt;[]<\/span> <\/b> intPairArr = nuevo <b> <span style=\"color:#660000;\"> Par&lt;Entero,Entero&gt;[10]<\/span> <\/b> ; <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 agregarElementos(intPairArr);\u00a0<\/tt><br \/>\n<tt> \u00a0 Par&lt;Integer,Integer&gt; par = intPairArr[1];<\/tt><br \/>\n<tt> \u00a0 Entero i = par.getFirst();<\/tt><br \/>\n<tt> \u00a0 par.setSecond(i);<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> addElements vac\u00edo est\u00e1tico (<b> Objeto[]<\/b> objetoArr) {<\/tt><br \/>\n<tt> \u00a0 objArr[0] = nuevo Par&lt;Integer,Integer&gt;(0,0);<\/tt><br \/>\n<tt> \u00a0 objArr[1] = nuevo Par&lt;String,String&gt;(\"\",\"\");\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ deber\u00eda fallar con ArrayStoreException<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<p>El compilador proh\u00edbe la creaci\u00f3n de matrices cuyo tipo de componente sea un tipo parametrizado concreto, como <tt> Par&lt;Entero,Entero&gt;<\/tt> en nuestro ejemplo.\u00a0 En la entrada anterior analizamos por qu\u00e9 es razonable que el compilador califique un<span style=\"color:#000000;\"> <tt> Par&lt;Entero,Entero&gt;[]<\/tt> <\/span> como ilegal.\u00a0 El problema clave es que el compilador y el sistema de ejecuci\u00f3n deben garantizar que una matriz sea una <i> homog\u00e9neo<\/i> secuencia de elementos del mismo tipo.\u00a0 Una de las comprobaciones de tipo, concretamente la comprobaci\u00f3n de almacenamiento de matriz realizada por la m\u00e1quina virtual en tiempo de ejecuci\u00f3n, no detecta la inserci\u00f3n infractora de un elemento extra\u00f1o. En el ejemplo, la segunda inserci\u00f3n en el <tt> agregarElementos<\/tt> El m\u00e9todo deber\u00eda fallar porque estaban agregando un par de cadenas a una matriz de valores integrales, pero no falla como se esperaba. Las razones fueron discutidas en la entrada anterior.<\/p>\n<p>Si no podemos usar matrices que contengan elementos cuyo tipo sea un tipo parametrizado concreto, \u00bfqu\u00e9 usamos como soluci\u00f3n alternativa?<\/p>\n<p>Consideremos 3 posibles soluciones:<\/p>\n<ul>\n<li>variedad de tipos crudos<\/li>\n<li>matriz de tipo parametrizado con comod\u00edn ilimitado<\/li>\n<li>colecci\u00f3n en lugar de matriz<\/li>\n<\/ul>\n<p>Si bien las matrices de tipos parametrizados concretos son ilegales, se permiten colecciones de tipos parametrizados concretos.<\/p>\n<p>Un tipo con par\u00e1metros comod\u00edn es una instanciaci\u00f3n de un tipo gen\u00e9rico donde al menos un argumento de tipo es un comod\u00edn.\u00a0 Ejemplos de tipos parametrizados con comodines son <tt> Colecci\u00f3n&lt;?&gt;<\/tt> , <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> , <tt> Comparador&lt;? s\u00faper cuerda&gt;<\/tt> y <tt> Par&lt;Cadena,?&gt;<\/tt> . Un tipo parametrizado con comod\u00edn denota una familia de tipos que comprende instancias concretas de un tipo gen\u00e9rico.\u00a0 El tipo de comod\u00edn que se utiliza determina qu\u00e9 tipos parametrizados concretos pertenecen a la familia.\u00a0 Por ejemplo, el tipo parametrizado comod\u00edn <tt> Colecci\u00f3n&lt;?&gt;<\/tt> denota la familia de todas las instancias del <tt> Recopilaci\u00f3n<\/tt> interfaz independientemente del tipo de argumento.\u00a0 El tipo parametrizado comod\u00edn <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> denota la familia de todos los tipos de lista donde el tipo de elemento es un subtipo de\u00a0 <tt> N\u00famero<\/tt> .\u00a0 El tipo parametrizado comod\u00edn <tt> Comparador&lt;? s\u00faper cuerda&gt;<\/tt> es la familia de todas las instancias del <tt> Comparador<\/tt> interfaz para tipos de argumentos de tipo que son supertipos de <tt> Cadena.<\/tt><\/p>\n<p><strong><em>Un tipo parametrizado con comod\u00edn no es un tipo en el sentido normal (diferente de una clase\/interfaz no parametrizada o un tipo sin formato).<\/em> <\/strong><\/p>\n<p>Se pueden utilizar tipos parametrizados comod\u00edn para escribir (como clases e interfaces no parametrizadas):<\/p>\n<ul>\n<li>como argumento y tipos de m\u00e9todos de retorno<\/li>\n<li>como tipo de campo o variable de referencia local<\/li>\n<li>como tipo de componente de una matriz como argumento de tipo de otros tipos parametrizados<\/li>\n<li>como tipo de objetivo en lanzamientos<\/li>\n<\/ul>\n<p>No s\u00f3lo los tipos pueden ser gen\u00e9ricos, sino que los m\u00e9todos tambi\u00e9n pueden serlo. Los m\u00e9todos est\u00e1ticos y no est\u00e1ticos, as\u00ed como los constructores, pueden tener par\u00e1metros de tipo. La sintaxis para la declaraci\u00f3n de par\u00e1metros de tipo formal es similar a la sintaxis para tipos gen\u00e9ricos. La secci\u00f3n de par\u00e1metro de tipo est\u00e1 delimitada por corchetes angulares y aparece antes del tipo de retorno del m\u00e9todo. Su sintaxis y significado son id\u00e9nticos a la lista de par\u00e1metros de tipo de un tipo gen\u00e9rico.<\/p>\n<p>Aqu\u00ed est\u00e1 el ejemplo de un gen\u00e9rico. <tt> m\u00e1ximo<\/tt> M\u00e9todo que calcula el mayor valor en una colecci\u00f3n de elementos de un tipo desconocido. <tt> A<\/tt> .<\/p>\n<p>Ejemplo (de un m\u00e9todo gen\u00e9rico):<\/p>\n<blockquote><p><tt> Colecciones de clase {<\/tt><br \/>\n<tt> \u00a0 est\u00e1tica p\u00fablica <b> <span style=\"color:#000099;\"> &lt;A ampl\u00eda Comparable&lt;A&gt;&gt; A<\/span> <\/b> max(Colecci\u00f3n&lt;<b> <span style=\"color:#000099;\"> A<\/span> <\/b> &gt; xs) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Iterador&lt;<b> <span style=\"color:#000099;\"> A<\/span> <\/b> &gt; xi = xs.iterador();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> A<\/span> <\/b> w = xi.siguiente();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 mientras (xi.hasNext()) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> A<\/span> <\/b> x = xi.siguiente();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 si (w.compareTo(x) &lt; 0) w = x;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 devolver w;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p><\/blockquote>\n<p>El <tt> m\u00e1ximo<\/tt> El m\u00e9todo tiene un par\u00e1metro de tipo, llamado<tt> A<\/tt> .\u00a0 Es un marcador de posici\u00f3n para el tipo de elemento de la colecci\u00f3n en la que funciona el m\u00e9todo. El par\u00e1metro de tipo tiene un l\u00edmite; debe ser un tipo que sea un subtipo de <tt> Comparable&lt;A&gt;<\/tt><\/p>\n<p>Ejemplo (del mismo tipo gen\u00e9rico, esta vez <i> con<\/i> l\u00edmites):<\/p>\n<blockquote><p><tt> interfaz p\u00fablica Comparable&lt;T&gt; {<\/tt><br \/>\n<tt> \u00a0 p\u00fablico int compararTo(T arg);<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> clase p\u00fablica TreeMap&lt;Key <b> <span style=\"color:#000066;\"> extiende Comparable&lt;Key&gt;<\/span> <\/b> ,Datos&gt;{<\/tt><br \/>\n<tt> \u00a0 Entrada de clase est\u00e1tica privada&lt;K,V&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 tecla K;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 valor V;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Entrada&lt;K,V&gt; izquierda = nula;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Entrada&lt;K,V&gt; derecha = nula;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Entrada&lt;K,V&gt; padre;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 Entrada transitoria privada&lt;Key,Data&gt; root = null;<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> \u00a0 Entrada privada&lt;Key,Data&gt; getEntry(Clave clave) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Entrada&lt;Key,Datos&gt; p = ra\u00edz;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Clave k = clave;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 mientras (p! = nulo) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 intcmp = k.<b> <span style=\"color:#990000;\"> comparar con (tecla p.)<\/span> <\/b> ;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 si (cmp == 0)<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver p;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 de lo contrario si (cmp &lt; 0)<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 p = p.izquierda;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 dem\u00e1s\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 p = p.derecha;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 devolver nulo;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 booleano p\u00fablico contiene clave (clave clave) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 devolver getEntry(clave) != nulo;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>En el ejemplo anterior, el par\u00e1metro de tipo <tt> Llave<\/tt> tiene el l\u00edmite <tt> Comparable&lt;Key&gt;<\/tt> .\u00a0 La especificaci\u00f3n de un l\u00edmite tiene dos efectos:<\/p>\n<ul>\n<li><i> Da acceso a los m\u00e9todos que el l\u00edmite especifica.<\/i> .\u00a0 En el ejemplo, el l\u00edmite <tt> Comparable&lt;Key&gt; <\/tt> da acceso a la <tt> comparar con<\/tt> m\u00e9todo que queremos invocar en la implementaci\u00f3n de nuestro <tt> \u00c1rbolMapa<\/tt> clase.<\/li>\n<\/ul>\n<ul>\n<li><i> S\u00f3lo se pueden utilizar tipos &#8220;dentro de l\u00edmites&#8221; para la creaci\u00f3n de instancias del tipo gen\u00e9rico.<\/i> \u00a0 En el ejemplo, un tipo parametrizado como <tt> \u00c1rbolMapa&lt;N\u00famero,Cadena&gt;<\/tt> ser\u00eda rechazado, porque el tipo <tt> N\u00famero<\/tt> no es un subtipo de <tt> Comparable&lt;N\u00famero&gt;<\/tt> .\u00a0 Un tipo parametrizado como <tt> TreeMap&lt;String,String&gt;<\/tt> ser\u00eda aceptado, porque el tipo String est\u00e1 dentro de los l\u00edmites, es decir, es un subtipo de <tt> Comparable&lt;String&gt;<\/tt> .<\/li>\n<\/ul>\n<p>Todas las clases, interfaces y tipos de enumeraci\u00f3n se pueden utilizar como par\u00e1metros de tipo vinculados, incluidos los tipos anidados e internos.\u00a0 Ni los tipos primitivos ni los tipos de matriz se utilizar\u00e1n como l\u00edmite de par\u00e1metro de tipo.<\/p>\n<p>Ejemplos (de l\u00edmites de par\u00e1metros de tipo):<\/p>\n<blockquote><p><tt> clase X0 &lt;T se extiende <b> <span style=\"color:#000099;\"> entero<\/span> <\/b> &gt; { ... }\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> clase X1 &lt;T se extiende <b> <span style=\"color:#000099;\"> Objeto[]<\/span> <\/b> &gt; { ... } <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> clase X2 &lt;T se extiende <b> <span style=\"color:#000099;\"> N\u00famero<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X3 &lt;T se extiende <b> <span style=\"color:#000099;\"> Cadena<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X4 &lt;T se extiende <b> <span style=\"color:#000099;\"> Ejecutable<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X5 &lt;T se extiende <b> <span style=\"color:#000099;\"> Hilo.Estado<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X6 &lt;T se extiende <b> <span style=\"color:#000099;\"> Lista<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X7 &lt;T se extiende <b> <span style=\"color:#000099;\"> Lista&lt;Cadena&gt;<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X8 &lt;T se extiende <b> <span style=\"color:#000099;\"> Lista&lt;? extiende el n\u00famero&gt;<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> clase X9 &lt;T se extiende <b> <span style=\"color:#000099;\"> \u00bfComparable&lt;? super n\u00famero&gt;<\/span> <\/b> &gt; { ... }<\/tt><br \/>\n<tt> la clase X10&lt;T se extiende <b> <span style=\"color:#000099;\"> Mapa.Entrada&lt;?,?&gt;<\/span> <\/b> &gt; { ... }<\/tt><\/p><\/blockquote>\n<p>El ejemplo de c\u00f3digo muestra que los tipos primitivos como <tt> entero<\/tt> y tipos de matrices como <tt> Objeto[] <\/tt> no est\u00e1n permitidos como l\u00edmite de par\u00e1metro de tipo.<\/p>\n<p>Tipos de clases, como <tt> N\u00famero<\/tt> o <tt> Cadena<\/tt> y tipos de interfaz, como <tt> Ejecutable<\/tt> , est\u00e1n permitidos como par\u00e1metro de tipo vinculado.<\/p>\n<p>Tipos de enumeraci\u00f3n, como <tt> Hilo.Estado<\/tt> Tambi\u00e9n se permiten como l\u00edmite de par\u00e1metro de tipo. <tt> Hilo.Estado<\/tt> es un ejemplo de un tipo anidado utilizado como l\u00edmite de par\u00e1metro de tipo.\u00a0 Tambi\u00e9n se permiten tipos interiores no est\u00e1ticos.<\/p>\n<p>Los tipos sin formato se permiten como par\u00e1metro de tipo vinculado; <tt> <span style=\"color:#000000;\"> Lista<\/span> <\/tt> es un ejemplo.<\/p>\n<p>Los tipos parametrizados se permiten como l\u00edmite de par\u00e1metro de tipo, incluidos tipos parametrizados concretos como <tt> Lista&lt;Cadena&gt;<\/tt> , tipos parametrizados con comodines acotados, como <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> y <tt> \u00bfComparable&lt;? s\u00faper largo&gt;<\/tt> y tipos parametrizados con comodines ilimitados, como <tt> Mapa.Entrada&lt;?,?&gt;<\/tt> .\u00a0 Un l\u00edmite que es un tipo parametrizado con comod\u00edn permite como argumento de tipo todos los tipos que pertenecen a la familia de tipos que denota el comod\u00edn.\u00a0 El tipo parametrizado comod\u00edn solo proporciona acceso restringido a campos y m\u00e9todos; las restricciones dependen del tipo de comod\u00edn.<\/p>\n<p>Ejemplo (de tipo parametrizado con comod\u00edn como par\u00e1metro de tipo vinculado):<\/p>\n<blockquote><p><tt> clase X&lt;<b> <span style=\"color:#000099;\"> \u00bfT extiende List&lt;? extiende el n\u00famero&gt;<\/span> <\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0 alg\u00fan m\u00e9todo p\u00fablico vac\u00edo (T t) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 t.add(nuevo Largo(0L));\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 N\u00famero n = t.remove(0);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> prueba de clase {<\/tt><br \/>\n<tt> \u00a0 public static void main(String[] args) {<\/tt><br \/>\n<tt> <b> <span style=\"color:#660000;\"> \u00a0\u00a0\u00a0\u00a0 <\/span> <\/b> <span style=\"color:#000000;\"> X&lt;AArrayList&lt;<\/span> <b> <span style=\"color:#000099;\"> Largo<\/span> <\/b> <span style=\"color:#000000;\"> &gt;&gt; x1 = nuevo X&lt;ArrayList&lt;Long&gt;&gt;();\u00a0<\/span> <\/tt><br \/>\n<tt> <span style=\"color:#000000;\"> \u00a0\u00a0\u00a0\u00a0 X&lt;AArrayList&lt;<\/span> <b> <span style=\"color:#000099;\"> Cadena<\/span> <\/b> <span style=\"color:#000000;\"> &gt;&gt; x2 = nuevo X&lt;ArrayList&lt;String&gt;&gt;(); <\/span> <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Variables de referencia de tipo<tt> t <\/tt> (el par\u00e1metro de tipo) se tratan como variables de referencia de un tipo comod\u00edn (el par\u00e1metro de tipo vinculado).\u00a0 En nuestro ejemplo, la consecuencia es que el compilador rechaza la invocaci\u00f3n de m\u00e9todos que toman un argumento del tipo &#8220;desconocido&#8221; que representa el par\u00e1metro de tipo, como por ejemplo <tt> Lista.a\u00f1adir<\/tt> , porque el l\u00edmite es un tipo parametrizado comod\u00edn con un l\u00edmite superior.<br \/>\nAl mismo tiempo el obligado <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> Determina los tipos que se pueden utilizar como argumentos de tipo. El compilador acepta todos los argumentos de tipo que pertenecen a la familia de tipos. <tt> Lista&lt;? extiende el n\u00famero&gt;<\/tt> , es decir, todos los subtipos de <tt> Lista<\/tt> con un argumento de tipo que es un subtipo de <tt> N\u00famero<\/tt> .<\/p>\n<p>Un par\u00e1metro de tipo se puede utilizar como l\u00edmite de otro par\u00e1metro de tipo.<\/p>\n<p>Ejemplo (de un par\u00e1metro de tipo utilizado como par\u00e1metro de tipo vinculado):<\/p>\n<blockquote><p><tt> clase triple<b> &lt;T&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0 privado T fst, snd, trd;<\/tt><br \/>\n<tt> \u00a0 p\u00fablico &lt;<b> Ud.<\/b> <b> <span style=\"color:#000099;\"> extiende T<\/span> <\/b> , <b> V <span style=\"color:#000099;\"> extiende T<\/span> <\/b> , <b> W. <span style=\"color:#000099;\"> extiende T<\/span> <\/b> &gt; Triple(U arg1, V arg2, W arg3) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 primero = arg1;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 nd = arg2;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 trd=arg3;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>En este ejemplo el par\u00e1metro de tipo <tt> t<\/tt> de la clase parametrizada se utiliza como l\u00edmite de los par\u00e1metros de tipo <tt> Ud.<\/tt> ,\u00a0 <tt> V<\/tt> y <tt> W.<\/tt> de un m\u00e9todo de instancia parametrizado de esa clase.<\/p>\n<p>Otras oportunidades para utilizar par\u00e1metros de tipo como l\u00edmites de otros par\u00e1metros de tipo incluyen situaciones en las que se define un tipo anidado dentro de un tipo gen\u00e9rico o se define una clase local dentro de un m\u00e9todo gen\u00e9rico.\u00a0 Incluso est\u00e1 permitido utilizar un par\u00e1metro de tipo como l\u00edmite de otro par\u00e1metro de tipo en la misma secci\u00f3n de par\u00e1metro de tipo.<\/p>\n<p>Un l\u00edmite que es una clase da acceso a todos sus miembros p\u00fablicos, es decir, campos p\u00fablicos, m\u00e9todos y tipos anidados. S\u00f3lo los constructores no son accesibles, porque no hay garant\u00eda de que una subclase del l\u00edmite tenga los mismos constructores que el l\u00edmite.<\/p>\n<p>Ejemplo (de una clase utilizada como l\u00edmite de un par\u00e1metro de tipo):<\/p>\n<blockquote><p><tt> clase publica <span style=\"color:#000000;\"> Superclase<\/span> {<\/tt><tt> \u00a0\u00a0\u00a0 \/\/ miembros est\u00e1ticos<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 enumeraci\u00f3n p\u00fablica EnumType {ESTO, ESO}<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Objeto est\u00e1tico p\u00fablico staticField;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 m\u00e9todo est\u00e1tico p\u00fablico est\u00e1tico vac\u00edo() {...}<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ miembros no est\u00e1ticos<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 clase p\u00fablica InnerClass {...}<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Objeto p\u00fablico campo no est\u00e1tico;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 m\u00e9todo p\u00fablico vac\u00edo no est\u00e1tico() {...}<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ constructores<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 Superclase p\u00fablica() {...}<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 \/\/ miembros privados<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 objeto privado campo privado;\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<p><tt> la clase final p\u00fablica SomeClass&lt;T se extiende <b> <span style=\"color:#006600;\"> Superclase<\/span> <\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 objeto T privado;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public SomeClass(T t) { objeto = t; }\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0 cadena p\u00fablica toString() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"tipo anidado est\u00e1tico\u00a0\u00a0\u00a0 : \"+T.EnumType.class+\"\\n\"\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"campo est\u00e1tico\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+T.staticField+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"m\u00e9todo est\u00e1tico\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+T.staticMethod()+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"tipo anidado no est\u00e1tico: \"+T.InnerClass.class+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"campo no est\u00e1tico\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+object.nonStaticField+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"m\u00e9todo no est\u00e1tico\u00a0\u00a0\u00a0\u00a0 : \"+object.nonStaticMethod()+\"\\n\"<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"constructor\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+(nueva T())+\"\\n\"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ error<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 +\"miembro privado\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 : \"+object.privateField+\"\\n\"\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ error\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>el atado <tt> Superclase<\/tt> da acceso a sus tipos anidados, campos y m\u00e9todos est\u00e1ticos y campos y m\u00e9todos no est\u00e1ticos.\u00a0 S\u00f3lo el constructor no es accesible.\u00a0 Esto se debe a que los constructores no se heredan. Cada subclase define sus propios constructores y no necesita soportar los constructores de su superclase.\u00a0 Por lo tanto, no hay garant\u00eda de que una subclase de <tt> Superclase<\/tt> tendr\u00e1 el mismo constructor que su superclase.<\/p>\n<p>El contexto en el que<tt> Enum&lt;E extiende Enum&lt;E&gt;&gt;<\/tt> &#8220;Lo que aparece es la declaraci\u00f3n del <tt> enumeraci\u00f3n<\/tt> clase en paquete <tt> java.lang<\/tt> :<\/p>\n<blockquote><p><tt> clase abstracta p\u00fablica <b> Enum&lt;E extiende Enum&lt;E&gt;&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>el tipo <tt> enumeraci\u00f3n<\/tt> es la clase base com\u00fan de todos los tipos de enumeraci\u00f3n.\u00a0 En Java, un tipo de enumeraci\u00f3n como <tt> Color<\/tt> se traduce en una clase <tt> Color<\/tt> que se extiende <tt> Enum&lt;Color&gt;<\/tt> . El prop\u00f3sito de la superclase. <tt> enumeraci\u00f3n<\/tt> es proporcionar una funcionalidad que sea com\u00fan a todos los tipos de enumeraci\u00f3n.<\/p>\n<p>Aqu\u00ed hay un boceto de la clase. <tt> enumeraci\u00f3n<\/tt> :<\/p>\n<blockquote><p><tt> clase abstracta p\u00fablica <b> Enum&lt;<span style=\"color:#000099;\"> mi<\/span> extiende Enum&lt;E&gt;&gt;<\/b> implementa Comparable&lt;<b> <span style=\"color:#000099;\"> mi<\/span> <\/b> &gt;, serializable {<\/tt><br \/>\n<tt> \u00a0 nombre de cadena final privado;<\/tt><br \/>\n<tt> \u00a0 nombre de cadena final p\u00fablica() {...}<\/tt><tt> \u00a0 ordinal final privado;<\/tt><br \/>\n<tt> \u00a0 p\u00fablico final int ordinal() {...}<\/tt><\/p>\n<p><tt> \u00a0 Enumeraci\u00f3n protegida (nombre de cadena, int ordinal) {...}<\/tt><\/p>\n<p><tt> \u00a0 cadena p\u00fablica\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 toString() { ... }<\/tt><br \/>\n<tt> \u00a0 p\u00fablico final booleano es igual (Objeto otro) {...}<\/tt><br \/>\n<tt> \u00a0 p\u00fablico final int hashCode() {...}<\/tt><br \/>\n<tt> \u00a0 Clon de objeto final protegido () lanza CloneNotSupportedException {...}<\/tt><br \/>\n<tt> \u00a0 p\u00fablico final int comparar con (<b> <span style=\"color:#000099;\"> mi<\/span> <\/b> o) {...}<\/tt><\/p>\n<p><tt> \u00a0 Clase final p\u00fablica&lt;<b> <span style=\"color:#000099;\"> mi<\/span> <\/b> &gt; getDeclaringClass() { ... }<\/tt><br \/>\n<tt> \u00a0 &lt;T est\u00e1tico p\u00fablico extiende Enum&lt;T&gt;&gt; T valueOf(Class&lt;T&gt; enumType, nombre de cadena) {...}<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>La caracter\u00edstica sorprendente de la declaraci\u00f3n &#8220;<tt> Enum&lt;E extiende Enum&lt;E&gt;&gt;<\/tt> &#8221; es el hecho de que la clase reci\u00e9n definida <tt> enumeraci\u00f3n<\/tt> y su par\u00e1metro de tipo reci\u00e9n definido <tt> mi <\/tt> aparecen en el l\u00edmite de ese mismo par\u00e1metro de tipo.\u00a0 Significa que el <tt> enumeraci\u00f3n<\/tt> Se debe crear una instancia del tipo para uno de sus subtipos.\u00a0 Para entender por qu\u00e9 esto tiene sentido, considere que cada tipo de enumeraci\u00f3n se traduce en un subtipo de <tt> enumeraci\u00f3n<\/tt> .<\/p>\n<p>Aqu\u00ed est\u00e1 el tipo de enumeraci\u00f3n artificial. <tt> Color<\/tt> :<\/p>\n<blockquote><p><tt> enumeraci\u00f3n <b> Color<\/b> {ROJO, AZUL, VERDE}<\/tt><\/p><\/blockquote>\n<p>El compilador lo traduce a la siguiente clase:<\/p>\n<blockquote><p><tt> clase final publica <b> Color<\/b> se extiende <b> Enum&lt;Color&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0 valores finales est\u00e1ticos p\u00fablicos de Color[]() { return (Color[])$VALUES.clone(); }<\/tt><br \/>\n<tt> \u00a0 valor de color est\u00e1tico p\u00fablico de (nombre de cadena) {...}<\/tt><tt> \u00a0 Color privado (Cadena s, int i) { super(s, i); }<\/tt><\/p>\n<p><tt> \u00a0 p\u00fablico est\u00e1tico final Color ROJO;<\/tt><br \/>\n<tt> \u00a0 p\u00fablico est\u00e1tico final Color AZUL;<\/tt><br \/>\n<tt> \u00a0 p\u00fablico est\u00e1tico final Color VERDE;<\/tt><\/p>\n<p><tt> \u00a0 Color final est\u00e1tico privado $VALUES[];<\/tt><\/p>\n<p><tt> \u00a0 est\u00e1tico {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 ROJO = nuevo Color(\"ROJO\", 0);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 AZUL = nuevo Color(\"AZUL\", 1);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 VERDE = nuevo Color(\"VERDE\", 2);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 $VALUES = (nuevo Color[] { ROJO, AZUL, VERDE });<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>La herencia tiene por efecto que el <tt> Color<\/tt> El tipo hereda todos los m\u00e9todos implementados en <tt> Enum&lt;Color&gt;<\/tt> .\u00a0 Entre ellos est\u00e1 el <tt> comparar con<\/tt> m\u00e9todo.\u00a0 El <tt> Color. comparar con<\/tt> El m\u00e9todo probablemente deber\u00eda tomar un <tt> Color<\/tt> como argumento.\u00a0 Para que esto suceda clase <tt> enumeraci\u00f3n<\/tt> es gen\u00e9rico y el <tt> Enum.compareTo<\/tt> el m\u00e9todo toma <tt> enumeraci\u00f3n<\/tt> par\u00e1metro de tipo <tt> mi <\/tt> como argumento.\u00a0 Como resultado, escriba <tt> Color<\/tt> derivado de <tt> Enum&lt;Color&gt;<\/tt> hereda un <tt> comparar con<\/tt> m\u00e9todo que requiere un <tt> Color<\/tt> como y argumento, exactamente como deber\u00eda.<br \/>\nSi analizamos la declaraci\u00f3n &#8220;<tt> Enum&lt;E extiende Enum&lt;E&gt;&gt;<\/tt> &#8220;Podemos ver que este patr\u00f3n tiene varios aspectos.<\/p>\n<p>En primer lugar, est\u00e1 el hecho de que el par\u00e1metro de tipo vinculado es el tipo mismo: &#8220;<tt> <b> enumeraci\u00f3n<\/b> &lt;E se extiende <b> enumeraci\u00f3n<\/b> &lt;E&gt;&gt;<\/tt> &#8220;. Se asegura de que solo los subtipos de tipo <tt> enumeraci\u00f3n<\/tt> est\u00e1n permitidos como argumentos de tipo. (Te\u00f3ricamente, escriba <tt> enumeraci\u00f3n<\/tt> podr\u00eda ser instanciado en s\u00ed mismo, como en <tt> Enum&lt;Enum&gt;<\/tt> , pero ciertamente esto no es lo que se pretende y es dif\u00edcil imaginar una situaci\u00f3n en la que tal creaci\u00f3n de instancias ser\u00eda \u00fatil).<\/p>\n<p>En segundo lugar, est\u00e1 el hecho de que el tipo vinculado al par\u00e1metro es el tipo parametrizado <tt> enumeraci\u00f3n<b> &lt;E&gt;<\/b> <\/tt> , que utiliza el par\u00e1metro de tipo <tt> mi<\/tt> como argumento de tipo del l\u00edmite. Esta declaraci\u00f3n asegura que la relaci\u00f3n de herencia entre un subtipo y una instanciaci\u00f3n de <tt> enumeraci\u00f3n<\/tt> es de la forma<tt> X extiende Enum&lt;X&gt;<\/tt> &#8220;. Un subtipo como &#8220;<tt> X extiende Enum&lt;Y&gt;<\/tt> &#8220;no se puede declarar debido al argumento de tipo <tt> Y<\/tt> no estar\u00eda dentro de los l\u00edmites; s\u00f3lo subtipos de <tt> Enum&lt;X&gt;<\/tt> est\u00e1n dentro de los l\u00edmites.<\/p>\n<p>En tercer lugar, est\u00e1 el hecho de que <tt> enumeraci\u00f3n<\/tt> es gen\u00e9rico en primer lugar.\u00a0 Significa que algunos de los m\u00e9todos de clase. <tt> enumeraci\u00f3n<\/tt> tomar un argumento o devolver un valor de un tipo desconocido (o depender de un tipo desconocido). Como ya sabemos, este tipo desconocido luego ser\u00e1 un subtipo <tt> inc\u00f3gnita<\/tt> de <tt> Enum&lt;X&gt;<\/tt> .\u00a0 Por lo tanto, en el tipo parametrizado <tt> Enum&lt;X&gt;<\/tt> , estos m\u00e9todos involucran el subtipo <tt> inc\u00f3gnita<\/tt> , y se heredan en el subtipo <tt> inc\u00f3gnita<\/tt> .\u00a0 El <tt> comparar con<\/tt> El m\u00e9todo es un ejemplo de tal m\u00e9todo; se hereda de la superclase a cada subclase y tiene una firma espec\u00edfica de subclase en cada caso.<\/p>\n<p>En resumen, la declaraci\u00f3n &#8220;<tt> Enum&lt;E extiende Enum&lt;E&gt;&gt;<\/tt> &#8221; se puede descifrar como: <tt> enumeraci\u00f3n<\/tt> es un tipo gen\u00e9rico del que solo se pueden crear instancias para sus subtipos, y esos subtipos heredar\u00e1n algunos m\u00e9todos \u00fatiles, algunos de los cuales toman argumentos espec\u00edficos del subtipo (o dependen del subtipo).<\/p>\n<p><b>Par\u00e1metros de clases de tipo de l\u00edmite inferior<\/b><\/p>\n<p>Los par\u00e1metros de tipo pueden tener varios l\u00edmites, como en <tt> clase Box&lt;T extiende N\u00famero&gt; {...}<\/tt> . Pero un par\u00e1metro de tipo no puede tener l\u00edmite inferior, es decir, una construcci\u00f3n como <tt> caja de clase&lt;T <b> excelente<\/b> N\u00famero&gt; {...}<\/tt> no est\u00e1 permitido.\u00a0 \u00bfPor qu\u00e9 no?\u00a0 La respuesta es: no tiene sentido porque no te comprar\u00eda nada, si estuviera permitido.\u00a0 Veamos por qu\u00e9 los par\u00e1metros de tipo de l\u00edmite inferior de las clases son confusos explorando lo que significa un l\u00edmite superior en un par\u00e1metro de tipo.<\/p>\n<p>El l\u00edmite superior de un par\u00e1metro de tipo tiene tres efectos:<\/p>\n<ol>\n<ol>\n<li><b> <i> Creaci\u00f3n de instancias restringida.<\/i> <\/b> El l\u00edmite superior restringe el conjunto de tipos que se pueden utilizar para la creaci\u00f3n de instancias del tipo gen\u00e9rico.\u00a0 Si declaramos un <tt> clase Box&lt;T extiende N\u00famero&gt; {...} <\/tt> entonces el compilador se asegurar\u00eda de que solo los subtipos de <tt> N\u00famero<\/tt> se puede utilizar como argumento de tipo.\u00a0 Es decir, un <tt> Caja&lt;N\u00famero&gt;<\/tt> o un <tt> Caja&lt;Largo&gt;<\/tt> est\u00e1 permitido, pero un <tt> Caja&lt;Objeto&gt;<\/tt> o <tt> Caja&lt;Cadena&gt;<\/tt> ser\u00eda rechazado<\/li>\n<\/ol>\n<\/ol>\n<p>Ejemplo (de creaci\u00f3n de instancias restringida debido a un l\u00edmite superior en un par\u00e1metro de tipo):<br \/>\n<tt> clase Box&lt;T extiende N\u00famero&gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 valor T privado;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 Caja p\u00fablica(T t) { valor = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><tt> prueba de clase {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Box&lt;Long&gt; boxOfLong = nuevo Box&lt;Long&gt;(0L);\u00a0\u00a0 <b> \/\/ bien<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Box&lt;String&gt; boxOfString = nuevo Box&lt;String&gt;(\"\"); <b> <span style=\"color:#330000;\"> \/\/ error: la cadena no est\u00e1 dentro de los l\u00edmites<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<ol>\n<li><b> <i> Acceso a miembros no est\u00e1ticos. <\/i> <\/b> El l\u00edmite superior da acceso a todos los m\u00e9todos y campos p\u00fablicos no est\u00e1ticos del l\u00edmite superior.\u00a0 En la implementaci\u00f3n de nuestra <tt> clase Box&lt;T extiende N\u00famero&gt; {...}<\/tt> podemos invocar todos los m\u00e9todos p\u00fablicos no est\u00e1ticos definidos en la clase <tt> N\u00famero<\/tt> , como <tt> valorint()<\/tt> por ejemplo.\u00a0 Sin el l\u00edmite superior, el compilador rechazar\u00eda cualquier invocaci\u00f3n de este tipo. Ejemplo (de acceso a miembros no est\u00e1ticos debido a un l\u00edmite superior en un par\u00e1metro de tipo):<\/li>\n<\/ol>\n<p><tt> clase Box&lt;T extiende N\u00famero&gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 valor T privado;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 Caja p\u00fablica(T t) { valor = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public int incremento() { valor de retorno.intValue()+1; } <b> \/\/ &lt;= ser\u00eda un error sin el n\u00famero vinculado<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p>\n<ol>\n<ol>\n<li><b> <i> Escriba Borrado. <\/i> <\/b> El l\u00edmite superior m\u00e1s a la izquierda se utiliza para borrar tipos y reemplaza el par\u00e1metro de tipo en el c\u00f3digo de bytes.\u00a0 en nuestro <tt> clase Box&lt;T extiende N\u00famero&gt; {...}<\/tt> todas las ocurrencias de <tt> t<\/tt> ser\u00eda reemplazado por el l\u00edmite superior <tt> N\u00famero<\/tt> .\u00a0 Por ejemplo, si la clase <tt> Caja<\/tt> tiene un campo privado de tipo <tt> t<\/tt> y un m\u00e9todo <tt> conjunto vac\u00edo (contenido T) <\/tt> para configurar este campo privado, entonces el campo ser\u00eda de tipo <tt> N\u00famero<\/tt> despu\u00e9s del borrado de tipo y el m\u00e9todo se traducir\u00eda a un m\u00e9todo <tt> conjunto vac\u00edo (contenido num\u00e9rico)<\/tt> .<\/li>\n<\/ol>\n<\/ol>\n<p>Ejemplo (de uso del l\u00edmite superior en un par\u00e1metro de tipo en el borrado de tipo &#8211; <i> antes<\/i> tipo borrado):<br \/>\n<tt> caja de clase&lt;<b> T extiende el n\u00famero<\/b> &gt; {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 privado <b> t<\/b> valor;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 caja p\u00fablica (<b> t<\/b> t) { valor = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }\u00a0<\/tt><\/p>\n<ol>\n<ol>Ejemplo (de uso del l\u00edmite superior en un par\u00e1metro de tipo en el borrado de tipo &#8211;<\/ol>\n<\/ol>\n<p><i> despu\u00e9s<\/i><\/p>\n<ol>\n<ol>tipo borrado):<\/ol>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><tt> caja de clase {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 privado <b> N\u00famero<\/b> valor;\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 caja p\u00fablica (<b> N\u00famero<\/b> t) { valor = t; }\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p>\n<ol>Adem\u00e1s, el l\u00edmite superior situado m\u00e1s a la izquierda aparece en otras ubicaciones, como modelos insertados autom\u00e1ticamente y m\u00e9todos de puente.<\/ol>\n<p>Si se permitieran l\u00edmites inferiores en los par\u00e1metros de tipo, \u00bfqu\u00e9 efectos secundarios tendr\u00edan o deber\u00edan tener? Si una construcci\u00f3n como <tt> caja de clase&lt;T <b> excelente<\/b> N\u00famero&gt; {...} <\/tt> estuvieran permitidos, \u00bfqu\u00e9 significar\u00eda?\u00a0 \u00bfQu\u00e9 significar\u00edan los 3 efectos secundarios de un l\u00edmite de par\u00e1metro de tipo superior (creaci\u00f3n de instancias restringida, acceso a miembros no est\u00e1ticos, borrado de tipo) para un l\u00edmite inferior?<\/p>\n<p><i> Instancias restringidas. <\/i> El compilador podr\u00eda restringir el conjunto de tipos que se pueden utilizar para la creaci\u00f3n de instancias del tipo gen\u00e9rico con un par\u00e1metro de tipo de l\u00edmite inferior.\u00a0 Por ejemplo, el compilador podr\u00eda permitir instanciaciones como <tt> Caja&lt;N\u00famero&gt;<\/tt> y <tt> Caja&lt;Objeto&gt;<\/tt> de un <tt> Caja&lt;T <b> excelente<\/b> N\u00famero&gt; <\/tt> y rechazar instanciaciones como <tt> Caja&lt;Largo&gt;<\/tt> o <tt> Caja&lt;Corto&gt;<\/tt> .\u00a0 Este ser\u00eda un efecto acorde con el efecto secundario restrictivo descrito para los l\u00edmites de par\u00e1metros de tipo superior.<\/p>\n<p><i> Acceso a miembros no est\u00e1ticos. <\/i> Un l\u00edmite de par\u00e1metro de tipo inferior no da acceso a ning\u00fan m\u00e9todo particular m\u00e1s all\u00e1 de los heredados de la clase. <tt> Objeto<\/tt> . En el ejemplo de <tt> Caja&lt;T <b> excelente<\/b> N\u00famero&gt; <\/tt> los supertipos de <tt> N\u00famero<\/tt> no tienen nada en com\u00fan, excepto que son tipos de referencia y por lo tanto subtipos de <tt> Objeto<\/tt> .\u00a0 El compilador no puede asumir que el campo de tipo <tt> t<\/tt> es de tipo <tt> N\u00famero<\/tt> o un subtipo del mismo.\u00a0 En cambio, el campo de tipo <tt> t<\/tt> puede ser de cualquier supertipo de <tt> N\u00famero<\/tt> , como <tt> Serializable<\/tt> o <tt> Objeto<\/tt> .\u00a0 La invocaci\u00f3n de un m\u00e9todo como <tt> valorint()<\/tt> ya no es seguro para tipos y el compilador tendr\u00eda que rechazarlo. Como consecuencia, el l\u00edmite de par\u00e1metro de tipo inferior no dar\u00eda acceso a miembros no est\u00e1ticos m\u00e1s all\u00e1 de los definidos en la clase. <tt> Objeto<\/tt> y por tanto tiene el mismo efecto que &#8220;sin l\u00edmites&#8221;.<\/p>\n<p><i> Tipo de borrado<\/i> .\u00a0 Siguiendo esta l\u00ednea de l\u00f3gica, no tiene sentido reemplazar las apariciones del par\u00e1metro de tipo por su l\u00edmite inferior m\u00e1s a la izquierda.\u00a0 Declarar un m\u00e9todo como el constructor <tt> Caja(<b> t<\/b> t) <\/tt> como constructor <tt> Caja(<b> N\u00famero<\/b> t)<\/tt> no tiene sentido, considerando que <tt> t<\/tt> es reemplazado por un supertipo de <tt> N\u00famero<\/tt> .\u00a0 Un <tt> Objeto<\/tt> podr\u00eda pasarse correctamente al constructor en una instanciaci\u00f3n <tt> Caja&lt;Objeto&gt;<\/tt> y el constructor lo rechazar\u00eda.\u00a0 Esto estar\u00eda completamente equivocado.\u00a0\u00a0 Entonces, el borrado de tipo reemplazar\u00eda todas las apariciones de la variable de tipo.<tt> t<\/tt> por tipo <tt> Objeto<\/tt> , y no por su l\u00edmite inferior.\u00a0 Una vez m\u00e1s, el l\u00edmite inferior tendr\u00eda el mismo efecto que &#8220;sin l\u00edmite&#8221;.<\/p>\n<p>\u00bfQuieres saber qu\u00e9 significar\u00eda si ambos bajaran? <i> _y_<\/i> \u00bfSe permitieron l\u00edmites superiores?\u00a0\u00a0 Personalmente, no quiero ni pensar en ello y preferir\u00eda archivarlo como &#8220;no manejable&#8221;, si me lo permite.<\/p>\n<p>La conclusi\u00f3n es: todo eso es un &#8220;<tt> excelente<\/tt> &#8220;Lo que te comprar\u00eda es la restricci\u00f3n de que s\u00f3lo los supertipos de <tt> N\u00famero<\/tt> se pueden utilizar como argumentos de tipo.\u00a0 E incluso eso a menudo se malinterpreta.\u00a0 NO significar\u00eda que <tt> clase Box&lt;T super N\u00famero&gt; {...}<\/tt> contiene s\u00f3lo instancias de supertipos de <tt> N\u00famero<\/tt> .\u00a0 Todo lo contrario, \u00a1como lo demuestra el siguiente ejemplo!<\/p>\n<p>Ejemplo (de uso del l\u00edmite superior en un par\u00e1metro de tipo en el borrado de tipo &#8211; <i> antes<\/i> tipo borrado):<\/p>\n<div style=\"margin-left:40px;\">\n<blockquote><p><tt> caja de clase&lt;<b> T s\u00faper n\u00famero<\/b> &gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 privado <b> t<\/b> valor;<\/tt><br \/>\n<tt> \u00a0\u00a0 caja p\u00fablica (<b> t<\/b> t) { valor = t; }<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<\/div>\n<p>Ejemplo (de uso del l\u00edmite superior en un par\u00e1metro de tipo en el borrado de tipo &#8211; <i> despu\u00e9s<\/i> tipo borrado):<\/p>\n<div style=\"margin-left:40px;\">\n<blockquote><p><tt> caja de clase {<\/tt><br \/>\n<tt> \u00a0\u00a0 privado <b> Objeto<\/b> valor;<\/tt><br \/>\n<tt> \u00a0\u00a0 caja p\u00fablica (<b> Objeto<\/b> t) { valor = t; }<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<\/div>\n<p>A <tt> caja de clase&lt;T <b> excelente<\/b> N\u00famero&gt; {...} <\/tt> ser\u00eda traducido por borrado de tipo a un <tt> Caja<\/tt> que contiene un <tt> Objeto<\/tt> El campo y su constructor se traducir\u00edan a <tt> Caja (Objeto t)<\/tt> . Eso es fundamentalmente diferente de un <tt> caja de clase&lt;T <b> se extiende<\/b> N\u00famero&gt; {...}<\/tt> , que se traducir\u00eda a un <tt> Caja<\/tt> que contiene un <tt> N\u00famero<\/tt> El campo y su constructor se traducir\u00edan a <tt> Caja(N\u00famero t)<\/tt> . En consecuencia, un <tt> Caja&lt;N\u00famero&gt;<\/tt> instanciado desde un<tt> clase Box&lt;T extiende N\u00famero&gt; {...}<\/tt> ser\u00eda diferente de un <tt> Caja&lt;N\u00famero&gt;<\/tt> instanciaci\u00f3n de un <tt> clase Box&lt;T super N\u00famero&gt; {...}<\/tt> , lo que probablemente cause confusi\u00f3n.\u00a0 Por este motivo, los l\u00edmites inferiores no tienen sentido en los par\u00e1metros de tipo de las clases.<\/p>\n<p>&nbsp;<\/p>\n<hr width=\"100%\" \/>\n<p>&nbsp;<\/p>\n<p><b>Par\u00e1metros de m\u00e9todos de tipo de l\u00edmite inferior<\/b><\/p>\n<p>Junto con los m\u00e9todos y sus tipos de argumentos, en ocasiones puede resultar \u00fatil un par\u00e1metro de tipo con un l\u00edmite inferior.<\/p>\n<p>Ejemplo (de un m\u00e9todo que se beneficiar\u00eda de un par\u00e1metro de tipo con un l\u00edmite inferior):<\/p>\n<blockquote><p><tt> clase Par&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 privado X primero;<\/tt><br \/>\n<tt> \u00a0\u00a0 privado Y segundo;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 p\u00fablico &lt;<b> Una s\u00faper X<\/b> ,<b> B s\u00faper Y<\/b> &gt; B addToMap(Map&lt;A,B&gt; map) { \/\/ error: el par\u00e1metro de tipo no puede tener un l\u00edmite inferior<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver map.put(primero, segundo);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> prueba de clase {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Par&lt;String,Long&gt; par = nuevo Par&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, N\u00famero&gt; mapa = HashMap&lt;CharSequence, N\u00famero&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 N\u00famero n\u00famero = par.addToMap(mapa);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>El <tt> agregarToMap()<\/tt> El m\u00e9todo agrega el contenido del par a un mapa.\u00a0 Cualquier mapa que pueda contener supertipos de <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> har\u00eda.\u00a0 el mapa <tt> poner()<\/tt> El m\u00e9todo devuelve el valor encontrado en el mapa para la clave dada, si ya existe una entrada clave-valor para la clave en el mapa.\u00a0 El valor de retorno del mapa. <tt> poner()<\/tt> El m\u00e9todo ser\u00e1 devuelto desde el <tt> agregarToMap()<\/tt> m\u00e9todo.\u00a0 En estas circunstancias, uno quisiera declarar el m\u00e9todo como se muestra arriba: El mapa est\u00e1 parametrizado con supertipos de los par\u00e1metros de tipo del par y el <tt> agregarToMap()<\/tt> El tipo de retorno del m\u00e9todo es el tipo de valor del mapa.<\/p>\n<p>Dado que el compilador no permite l\u00edmites inferiores en los par\u00e1metros de tipo, necesitamos una soluci\u00f3n alternativa.<\/p>\n<p>Una soluci\u00f3n que me viene a la mente es el uso de un comod\u00edn, porque los comodines pueden tener un l\u00edmite inferior.\u00a0 A continuaci\u00f3n se ofrece una soluci\u00f3n alternativa mediante el uso de un comod\u00edn.<\/p>\n<p>Ejemplo (de una soluci\u00f3n alternativa para el ejemplo anterior usando comodines):<\/p>\n<blockquote><p><tt> clase Par&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 privado X primero;<\/tt><br \/>\n<tt> \u00a0\u00a0 privado Y segundo;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 public <b> Objeto<\/b> addToMap(Mapa&lt;<b> ? S\u00faper X<\/b> , <b> ? s\u00faper Y<\/b> mapa &gt;) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver map.put(primero, segundo);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> prueba de clase {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Par&lt;String,Long&gt; par = nuevo Par&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, N\u00famero&gt; mapa = HashMap&lt;CharSequence, N\u00famero&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 N\u00famero n\u00famero = <b> (N\u00famero)<\/b> par.addToMap(mapa);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Funciona, excepto que no hay forma de declarar el tipo de devoluci\u00f3n deseado.\u00a0 Ser\u00eda el supertipo de <tt> Y<\/tt> que el compilador captura del tipo de mapa, pero no hay sintaxis para especificarlo.\u00a0 No debemos declarar el tipo de devoluci\u00f3n a &#8220;<tt> ? s\u00faper Y<\/tt> &#8220;, porque &#8220;<tt> ? s\u00faper Y<\/tt> &#8221; es un comod\u00edn y no un tipo y, por lo tanto, no est\u00e1 permitido como tipo de devoluci\u00f3n. No tenemos otra opci\u00f3n y debemos usar <tt> Objeto<\/tt> en lugar de ello, como el tipo de retorno de nuestro m\u00e9todo.\u00a0 Este tipo de devoluci\u00f3n bastante inespec\u00edfico obliga a su vez a quienes llaman al <tt> agregarToMap()<\/tt> m\u00e9todo para convertir el valor de retorno hacia abajo desde <tt> Objeto<\/tt> a su tipo real.\u00a0 Esto no es exactamente lo que ten\u00edamos en mente.<\/p>\n<p>Otra soluci\u00f3n es el uso de m\u00e9todos est\u00e1ticos.\u00a0 A continuaci\u00f3n se ofrece una soluci\u00f3n alternativa con un m\u00e9todo est\u00e1tico en lugar de uno no est\u00e1tico.<\/p>\n<p>Ejemplo (de una soluci\u00f3n alternativa para el ejemplo anterior utilizando un m\u00e9todo est\u00e1tico):<\/p>\n<blockquote><p><tt> clase Par&lt;X,Y&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0 privado X primero;<\/tt><br \/>\n<tt> \u00a0\u00a0 privado Y segundo;<\/tt><br \/>\n<tt> \u00a0\u00a0 ...<\/tt><br \/>\n<tt> \u00a0\u00a0 public <b> est\u00e1tico<\/b> &lt;<b> A<\/b> ,<b> B<\/b> ,INC\u00d3GNITA <b> extiende A<\/b> ,Y <b> extiende B<\/b> &gt; B addToMap(Par&lt;X,PAR Y&gt;, Map&lt;<b> A<\/b> ,<b> B<\/b> mapa &gt;) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 return map.put(par.primero,par.segundo);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><br \/>\n<tt> prueba de clase {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0 public static void main(String[] args) {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Par&lt;String,Long&gt; par = nuevo Par&lt;&gt;(\"ABC\",42L);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 Map&lt;CharSequence, N\u00famero&gt; mapa = HashMap&lt;CharSequence, N\u00famero&gt;();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0 N\u00famero n\u00famero = <b> Par<\/b> .addToMap(<b> par<\/b> ,mapa);<\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>el generico <tt> agregarToMap()<\/tt> El m\u00e9todo tiene cuatro par\u00e1metros de tipo: dos marcadores de posici\u00f3n. <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> para el tipo de par y dos marcadores de posici\u00f3n <tt> A<\/tt> y <tt> B <\/tt> para el tipo de mapa. <tt> A<\/tt> y <tt> B<\/tt> son supertipos de <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> , porque <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> \u00a0 se declaran con <tt> A<\/tt> y <tt> B<\/tt> como sus l\u00edmites superiores. (Tenga en cuenta que los par\u00e1metros de tipo del m\u00e9todo gen\u00e9rico <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> no tiene nada que ver con el <tt> Par<\/tt> clase <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> par\u00e1metros.\u00a0 los nombres <tt> inc\u00f3gnita<\/tt> y <tt> Y<\/tt> se reutilizan para el m\u00e9todo gen\u00e9rico para hacerlos f\u00e1cilmente reconocibles como par\u00e1metros de tipo del par. Usando cuatro par\u00e1metros de tipo podemos declarar el tipo de retorno preciso como lo deseemos: es el mismo tipo que el tipo de valor del mapa.<\/p>\n<p>Ejemplo (de uso ilegal de par\u00e1metro de tipo en el contexto est\u00e1tico de una clase gen\u00e9rica):<\/p>\n<blockquote><p><tt> clase alguna clase<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> inicializador est\u00e1tico, campo est\u00e1tico, m\u00e9todo est\u00e1tico<\/i><br \/>\n<tt> \u00a0 <b> est\u00e1tico<\/b> {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 AlgunaClase&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> Prueba &gt; = nueva SomeClass&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> &gt;(); <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 privado <b> est\u00e1tico<\/b> <b> <span style=\"color:#000099;\"> t<\/span> <\/b> informaci\u00f3n global;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 public\u00a0 <b> est\u00e1tico<\/b> <b> <span style=\"color:#000099;\"> t <\/span> <\/b> getGlobalInfo() {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 devolver informaci\u00f3n global;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> inicializador no est\u00e1tico, campo no est\u00e1tico, m\u00e9todo no est\u00e1tico<\/i><br \/>\n<tt> \u00a0 {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 AlgunaClase&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> Prueba &gt; = nueva SomeClass&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> &gt;();<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 privado\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> t<\/span> <\/b> informaci\u00f3n local;<\/tt><br \/>\n<tt> \u00a0 public\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> t<\/span> <\/b> obtener informaci\u00f3n local() {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 devolver informaci\u00f3n local;<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> tipos anidados est\u00e1ticos<\/i><br \/>\n<tt> \u00a0 public <b> est\u00e1tico<\/b> <b> clase<\/b> El error extiende la excepci\u00f3n {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 final privada <b> <span style=\"color:#000099;\"> t<\/span> <\/b> informaci\u00f3n;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 fracaso p\u00fablico (<b> <span style=\"color:#000099;\"> t<\/span> <\/b> t) { informaci\u00f3n = t; }\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getInfo() { devolver informaci\u00f3n; }\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 privado <b> interfaz<\/b> Copiable {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 <b> <span style=\"color:#000099;\"> t<\/span> <\/b> Copiar();\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 privado <b> enumeraci\u00f3n<\/b> Estado {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 V\u00c1LIDO, NO V\u00c1LIDO;<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 privado <b> <span style=\"color:#000099;\"> t<\/span> <\/b> informaci\u00f3n; \/\/ error<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 setInfo p\u00fablica vac\u00eda (<b> <span style=\"color:#000099;\"> t<\/span> <\/b> t) { informaci\u00f3n = t; } <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getInfo() { devolver informaci\u00f3n; }\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> tipos anidados no est\u00e1ticos<\/i><br \/>\n<tt> \u00a0 public <b> clase<\/b> Accesorio {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getInfo() { return informaci\u00f3n local; }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>El ejemplo ilustra que el par\u00e1metro de tipo no se puede utilizar en el contexto est\u00e1tico de una clase gen\u00e9rica.\u00a0 Tambi\u00e9n muestra que las interfaces anidadas y los tipos de enumeraci\u00f3n se consideran miembros de tipo est\u00e1tico de la clase.\u00a0 S\u00f3lo las clases internas, es decir, las clases anidadas no est\u00e1ticas, pueden utilizar el par\u00e1metro de tipo de la clase gen\u00e9rica adjunta.<\/p>\n<p>El alcance del par\u00e1metro de tipo de una interfaz es la definici\u00f3n completa de la interfaz, excepto cualquier campo o tipo anidado.\u00a0 Esto se debe a que los campos y tipos anidados definidos en una interfaz son impl\u00edcitamente est\u00e1ticos.<\/p>\n<p>Ejemplo (de uso ilegal de par\u00e1metro de tipo en una interfaz gen\u00e9rica):<\/p>\n<blockquote><p><tt> interfaz alguna interfaz<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> campo<\/i><br \/>\n<tt> \u00a0 AlgunaClase&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> Valor &gt; = nuevo SomeClass&lt;<b> <span style=\"color:#000099;\"> t<\/span> <\/b> &gt;();\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> tipo anidado<\/i><br \/>\n<tt> \u00a0 <b> clase<\/b> Accesorio {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 public <b> <span style=\"color:#000099;\"> t <\/span> <\/b> obtener informaci\u00f3n() {\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <b> <span style=\"color:#660000;\"> \/\/ error<\/span> <\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 valor de retorno.getGlobalInfo();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 \/\/ <\/tt> <i> metodos<\/i><br \/>\n<tt> \u00a0 <b> <span style=\"color:#000099;\"> t<\/span> <\/b> obtenerValor();<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>El ejemplo muestra que los campos de una interfaz son impl\u00edcitamente est\u00e1ticos, por lo que el par\u00e1metro de tipo no se puede utilizar en ninguna parte de la declaraci\u00f3n de un campo de una interfaz gen\u00e9rica.\u00a0 De manera similar, la clase anidada se considera una clase anidada est\u00e1tica, no una clase interna, y por esta raz\u00f3n el uso del par\u00e1metro de tipo en cualquier parte de la clase anidada es ilegal.<\/p>\n<p><b> <i> Soluci\u00f3n alternativa para clases e interfaces est\u00e1ticas anidadas:<\/i> <\/b><\/p>\n<p>En el caso de clases e interfaces anidadas est\u00e1ticas, esto no es una calamidad importante.\u00a0 Como soluci\u00f3n alternativa, podemos generar la clase est\u00e1tica o la interfaz misma.<\/p>\n<p>Ejemplo (soluci\u00f3n alternativa: generar el tipo est\u00e1tico anidado):<\/p>\n<blockquote><p><tt> envoltura de clase<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 final privada <b> <span style=\"color:#000099;\"> t<\/span> <\/b> el objeto;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 envoltura p\u00fablica (<b> <span style=\"color:#000099;\"> t<\/span> <\/b> t) { elObjeto = t; }<\/tt><br \/>\n<tt> \u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getWrapper() { devolver elObjeto; }<\/tt><tt> \u00a0 p\u00fablico inmutable<b> &lt;T&gt;<\/b> hacerInmutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver nuevo inmutable<b> &lt;T&gt;<\/b> (elObjeto);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 p\u00fablico mutable<b> &lt;T&gt;<\/b> hacerMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver nuevo mutable<b> &lt;T&gt;<\/b> (elObjeto);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 est\u00e1tico privado &lt;A&gt; A makeClone (A theObject) {...}<\/tt><\/p>\n<p><tt> \u00a0 clase final est\u00e1tica p\u00fablica inmutable<b> &lt;A&gt;<\/b> { <b> \/\/ ahora es una clase gen\u00e9rica<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 final privada <b> A<\/b> el objeto;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 p\u00fablico inmutable (<b> A<\/b> argumento) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 elObjeto = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 public <b> A<\/b> getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver makeClone(elObjeto);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 clase est\u00e1tica p\u00fablica mutable<b> &lt;A&gt;<\/b> {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... similar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>No existe tal soluci\u00f3n para los tipos de enumeraci\u00f3n anidados porque no pueden ser gen\u00e9ricos.<\/p>\n<p><b> <i> Soluci\u00f3n alternativa para clases est\u00e1ticas anidadas:<\/i> <\/b><\/p>\n<p>Si el tipo est\u00e1tico anidado es una clase, una soluci\u00f3n alternativa ser\u00eda convertir la clase est\u00e1tica en una clase interna no est\u00e1tica.<\/p>\n<p>Ejemplo (soluci\u00f3n alternativa: utilice una clase interna):<\/p>\n<blockquote><p><tt> envoltura de clase<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 final privada <b> <span style=\"color:#000099;\"> t<\/span> <\/b> el objeto;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 envoltura p\u00fablica (<b> <span style=\"color:#000099;\"> t<\/span> <\/b> t) { elObjeto = t; }<\/tt><br \/>\n<tt> \u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getWrapper() { devolver elObjeto; }<\/tt><tt> \u00a0 p\u00fablico mutable makeMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver <b> este.<\/b> nuevo Mutable(elObjeto);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 p\u00fablico inmutable makeImmutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver <b> este.<\/b> nuevo Inmutable (el Objeto);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 est\u00e1tico privado &lt;A&gt; A makeClone (A theObject) {...}<\/tt><\/p>\n<p><tt> \u00a0 clase final p\u00fablica inmutable {\u00a0 <b> \/\/ ya no es una clase est\u00e1tica<\/b> <\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 final privada <b> t<\/b> el objeto;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 p\u00fablico inmutable (<b> t<\/b> argumento) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 elObjeto = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 public <b> t<\/b> getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver makeClone(elObjeto);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 clase p\u00fablica mutable\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... similar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Esta soluci\u00f3n viene con una cierta cantidad de gastos generales porque todas las clases internas tienen una referencia oculta a una instancia del tipo externo, que en este ejemplo no necesitan ni aprovechan; la referencia oculta es s\u00f3lo equipaje.\u00a0 A menudo, las clases internas se combinan con interfaces para mantener la clase interna como un detalle de implementaci\u00f3n privado de la clase adjunta.\u00a0 Podemos hacer lo mismo aqu\u00ed.<\/p>\n<p>Ejemplo (la soluci\u00f3n alternativa anterior se perfeccion\u00f3):<\/p>\n<blockquote><p><tt> envoltura de clase<b> <span style=\"color:#000099;\"> &lt;T&gt;<\/span> <\/b> {<\/tt><br \/>\n<tt> \u00a0 final privada <b> <span style=\"color:#000099;\"> t<\/span> <\/b> el objeto;<\/tt><\/p><\/blockquote>\n<blockquote><p><tt> \u00a0 envoltura p\u00fablica (<b> <span style=\"color:#000099;\"> t<\/span> <\/b> t) { elObjeto = t; }<\/tt><br \/>\n<tt> \u00a0 public <b> <span style=\"color:#000099;\"> t<\/span> <\/b> getWrapper() { devolver elObjeto; }<\/tt><tt> \u00a0 p\u00fablico mutable<b> &lt;T&gt;<\/b> hacerMutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver this.new Mutable(theObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 p\u00fablico inmutable<b> &lt;T&gt;<\/b> hacerInmutable() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 devolver this.new Immutable(theObject);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 est\u00e1tico privado &lt;A&gt; A makeClone (A theObject) {...}<\/tt><\/p>\n<p><tt> \u00a0 <b> interfaz p\u00fablica <\/b> Inmutable&lt;S&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 S getWrappedItem();<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> interfaz p\u00fablica <\/b> Mutable&lt;S&gt; {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 S getWrappedItem();<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 vac\u00edo setWrappedItem (S arg);<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> privado<\/b> Implementaci\u00f3n inmutable de clase final <b> implementa Inmutable&lt;T&gt;<\/b> {\u00a0<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 final privado T elObjeto;<\/tt><\/p>\n<p><tt> \u00a0\u00a0\u00a0\u00a0\u00a0 Implementaci\u00f3n inmutable p\u00fablica (T arg) {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 elObjeto = makeClone(arg);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 p\u00fablico T getWrappedItem() {<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 devolver makeClone(elObjeto);<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0 }<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> \u00a0 <b> privado<\/b> clase MutableImplementaci\u00f3n <b> implementa Mutable&lt;T&gt;<\/b> {\u00a0<\/tt><br \/>\n<tt> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ... similar ...<\/tt><br \/>\n<tt> \u00a0 }<\/tt><br \/>\n<tt> }<\/tt><\/p><\/blockquote>\n<p>Como puede ver, las interfaces p\u00fablicas anidadas deben ser gen\u00e9ricas, mientras que las clases privadas internas pueden usar el par\u00e1metro de tipo de la clase adjunta.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<table width=\"100%\" cellpadding=\"10\">\n<tbody>\n<tr valign=\"TOP\">\n<td colspan=\"2\" width=\"68%\"><b>\u00a0<\/b><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\"><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Consulte estas preguntas frecuentes para obtener m\u00e1s informaci\u00f3n: <a href=\"http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1\" rel=\"nofollow\">http:\/\/www.angelikalanger.com\/GenericsFAQ\/JavaGenericsFAQ.html#SECTION1<\/a> Aqu\u00ed, de forma resumida, algunos puntos importantes de estas preguntas frecuentes. Ejemplo (de tipo gen\u00e9rico): clase Par&lt;X,Y&gt; {\u00a0 \u00a0 privado X primero; \u00a0 privado Y segundo; \u00a0 Par p\u00fablico(X a1, Y a2) { \u00a0\u00a0\u00a0 primero = a1; \u00a0\u00a0\u00a0 segundo = a2; \u00a0 } \u00a0 public X [&hellip;]<\/p>\n","protected":false},"author":65283547,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Generics in short form","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1017],"tags":[18369,2549795,6280762],"class_list":["post-31","post","type-post","status-publish","format-standard","hentry","category-java","tag-genericos","tag-java","tag-genericos-de-java"],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4CoHV-v","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/users\/65283547"}],"replies":[{"embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":8,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31\/revisions"}],"predecessor-version":[{"id":42,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/posts\/31\/revisions\/42"}],"wp:attachment":[{"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/media?parent=31"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/categories?post=31"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vkrastev1blog.com\/wp-json\/wp\/v2\/tags?post=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}