Este artículo analiza las diferencias entre JDK1.4, JDK1.5 y JDK1.6 en la programación de Java en combinación con ejemplos. Compártelo para su referencia, como sigue:
En pocas palabras: hay dos mayores diferencias entre 1.4 y 1.5. Una es que 1.5 tiene genéricos, y el otro 1.5 puede encapsular automáticamente los tipos de datos encapsulados de ocho tipos de datos básicos. Es decir, el entero A = 4 no está permitido. No hay mucha diferencia entre 1.5 y 1.6. 1.6 Creo que la mayoría de los cambios son la GUI, que proporciona una gran gestión y extensión de diseño conveniente.
Durante este período, me uní a una empresa de gobierno electrónico y usé WebLogic8. Entonces usemos JDK1.4. Eclipse cambió la versión JDK. Sin embargo, los proyectos anteriores se han vuelto básicamente populares.
★ nuevas características de JDK1.5:
1. Genéricos
2 Empaque automático/Unboxing
3 para cada
4 importación estática
5 parámetros de longitud variable
1. Generics (evite ejecutar errores que pueden ser causados por el tipo de fundición)
Por ejemplo:
ArrayList list = new ArrayList (); list.add (nuevo entero (3)); list.add (nuevo entero (4)); int i = ((entero) (list.get (0))). parseInt ();
Muy problemático
ArrayList <Integer> list = new ArrayList <Integer> (); list.add (nuevo entero (3)); list.add (nuevo entero (4)); int i = list.get (0) .ParseInt ();
2 Empaque automático/Unboxing
La última oración del ejemplo anterior se puede cambiar a:
La copia del código es la siguiente: int i = list.get (0);
Porque el tipo original y la clase de envoltorio correspondiente no necesitan convertirse explícitamente
3 para cada
Mejora de bucles
int a [] = {......}; // Inicializar para (int i: a) {......}No use el anterior i = 0; i <a.length; i ++
4 importación estática
Java.math anteriormente sintonizado
La copia del código es la siguiente: Math.Sqrt ();
Ahora static import java.lang.math.sqrt;
sqrt ();
Es equivalente a tener este método en su propia clase
5 parámetros de longitud variable
int sum (int ... intlist) {int sum; suma = 0; for (int i = 0; i <intlist.length; i ++) {sum+= intlist [i]; } suma de retorno;}Hay algún parámetro, trátelo como una matriz
★ nuevas características de JDK6.0
Enumeración de anotación de la declaración mejorada para bucle de parámetros variádicos del método estático "oculto" (vararg)
Los comodines y el retorno de covarianza mejoraron para las declaraciones de bucle
Para iterar sobre conjuntos y matrices, el bucle mejorado proporciona una sintaxis simple y compatible. Hay dos puntos que vale la pena mencionar:
1. En un bucle, la expresión de inicialización se calcula solo una vez. expresión int expresión
No mejorado para:
int sum = 0; Integer [] números = CompuTenumbers (); para (int i = 0; i <numbers.length; i ++) sum+= números [i];
Mejorado para:
int sum = 0; for (int número: CompuTenumbers ()) sum += número;
limitación
No se puede acceder a iterador o subíndice durante mejorado para la iteración de bucle
Consulte el siguiente ejemplo:
for (int i = 0; i <numbers.length; i ++) {if (i! = 0) System.out.print (","); System.out.print (números [i]);}Aquí hay otro ejemplo:
para (iterator <Integer> it = n.Iterator (); it.hasNext ();) if (it.next () <0) it.remove ();
Comentario
El procesamiento de comentarios es un gran tema. Debido a que este artículo se centra solo en las características del lenguaje central, no tenemos la intención de cubrir todas sus posibles formas y dificultades. Discutiremos las anotaciones incorporadas (supresión de las tarjetas, desaprobado y anulación) y las limitaciones del procesamiento de anotaciones generales.
Suprimir advertencias
Este comentario desactiva las advertencias del compilador a nivel de clase o método. A veces sabe más claramente que el compilador que el código debe usar un método rechazado o realizar alguna acción que no pueda determinar estáticamente si el tipo seguro es tipo seguro y usar:
@SupessWarnings ("Deprecation") public static void selfDestruct () {thread.currentThread (). Stop ();}Esto es probablemente lo más útil de las anotaciones incorporadas. Desafortunadamente, Javac para 1.5.0_04 no lo admite. Pero 1.6 lo admite, y Sun está trabajando para portarlo hacia atrás en 1.5.
Esta anotación es compatible con Eclipse 3.1, y otros IDE también pueden respaldarla. Esto le permite liberar completamente el código de la advertencia. Si hay una advertencia en el momento de la compilación, puede estar seguro de que la acaba de agregar, para ayudar a ver el código que puede ser inseguro. Con la adición de genéricos, será más útil de usar.
Desapercibido
Desafortunadamente, en desuso no es tan útil. Originalmente tenía la intención de reemplazar la etiqueta javadoc @Depreced, pero dado que no contiene ningún campo, no hay forma de sugerir qué usuarios de clases o métodos desaprobados deben usar como reemplazo. mayoría
Ambos usos requieren la etiqueta Javadoc y esta anotación.
Anular
Anverride dice que el método que anota debe anular los métodos con la misma firma en la superclase:
@OverridePublic int hashcode () {...}Mirando el ejemplo anterior, si "C" no se capitaliza en hashcode, no habrá errores en el momento de la compilación, pero el método no se llamará como se esperaba en el tiempo de ejecución. Al agregar la etiqueta de anulación, el compilador solicitará si realmente realizó la reescritura.
Esto también es útil en situaciones en las que cambian las superclase. Si se agrega un nuevo parámetro al método, y el método en sí mismo se renombra, la subclase de repente no se compilará porque ya no reescribe nada de la superclase.
Otras notas
Los comentarios son muy útiles en otros escenarios. Cuando no se trata de modificar el comportamiento directamente, sino mejorar el comportamiento, especialmente al agregar código básico, la anotación funciona muy bien en marcos como EJB y servicios web.
Los comentarios no pueden usarse como preprocesadores. El diseño de Sun evita específicamente la modificación del código de byte de la clase por completo debido a los comentarios. Esto le permite comprender correctamente los resultados del lenguaje, y las herramientas como IDE también pueden realizar un análisis de código en profundidad y la refactorización.
El comentario no es una bala de plata. Cuando lo encontré por primera vez, la gente intentó probar varias técnicas. Consulte las siguientes sugerencias obtenidas de otros:
clase pública foo {@propertyprivate int bar;}La idea es crear automáticamente métodos Getter y Setter para barra de campo privada. Desafortunadamente, hay dos fallas en esta idea: 1) No funciona, y 2) hace que el código sea difícil de leer y procesar. Es imposible de implementar, porque como se mencionó anteriormente, Sun previene específicamente la modificación de las clases con comentarios.
Incluso si es posible, no es una buena idea porque hace que el código sea mal legible. La primera vez que vea este código, no sabrá que el comentario crea el método. Además, si necesita realizar algunas operaciones dentro de estos métodos en el futuro, los comentarios son inútiles. En resumen, no intente hacer cosas que el código normal pueda hacer con los comentarios.
enumerar
Enum es muy parecido a una declaración de int nota pública de int, que se ha utilizado como un valor de Enum durante muchos años. La mejora más grande y obvia de INT es la seguridad del tipo: no puede reemplazar por error otro tipo con un tipo de enumeración, que es diferente de INT, y todos los INT son los mismos para el compilador. Con muy pocas excepciones, todas las estructuras INT de estilo Enum generalmente deben reemplazarse con instancias enum.
La enumeración proporciona algunas características adicionales. Las dos clases prácticas enummap y enumset son implementaciones de conjunto estándar especialmente optimizadas para la enumeración. Si sabe que una colección contiene solo tipos de ENUM, debe usar estas colecciones especiales en lugar de hashmap o hashset.
En la mayoría de los casos, puede usar ENUM para reemplazar todos los ints finales estáticos públicos en el código. Son comparables y se pueden importar estáticamente, por lo que las referencias a ellas parecen ser equivalentes, incluso para las clases internas (o tipos de enumes internos). Tenga en cuenta que al comparar los tipos de ENUM, las instrucciones que los declaran indican sus valores secuenciales.
Método estático "oculto"
Dos métodos estáticos aparecen en todas las declaraciones de tipo enum. Debido a que son métodos estáticos en las subclases de enum, no los métodos de Enum en sí mismo, no aparecen en Javadoc de Java.lang.enum.
El primero es valores (), que devuelve una matriz de todos los valores posibles del tipo de enumeración.
El segundo es valueOf (), que devuelve un tipo enum para la cadena proporcionada, que debe coincidir exactamente con la declaración del código fuente.
método
Uno de nuestros aspectos favoritos sobre los tipos de Enum es que puede tener métodos. En el pasado, es posible que tenga que escribir algún código para convertir el intento público estático público y convertirlo del tipo de base de datos a una URL JDBC. Ahora, el tipo de enum en sí se puede hacer con un completo
Métodos para manipular el código. Aquí hay un ejemplo, que incluye el método abstracto del tipo de enum de DataBASEType y la implementación proporcionada en cada instancia de Enum:
public enum dataBASEType {Oracle {public String getJdbcurl () {...}}, mySql {public String getJdbcurl () {...}}; public abstract String getJdbcurl ();}Ahora el tipo de enumación puede proporcionar directamente sus métodos prácticos. Por ejemplo:
DataBAsetype dbtype = ...; Cadena jdbcurl = dbtype.getjdbcurl ();
Para obtener la URL, debe saber de antemano dónde está el método de utilidad.
Vararg
El uso de parámetros mutables correctamente limpia algún código de basura. Un ejemplo típico es un método de registro con un número variable de parámetros de cadena:
Log.log (string código) log.log (código de cadena, cadena arg) log.log (código de cadena, string arg1, string arg2) log.log (string code, string [] args)
Al discutir los parámetros variables, es interesante que si reemplaza los primeros cuatro ejemplos con nuevos parámetros variables, será compatible:
Copie el código de la siguiente manera: log.log (código de cadena, cadena ... args)
Todos los parámetros mutables son compatibles con la fuente, es decir, si todos los programas de llamadas del método log () se recompilan, los cuatro métodos pueden reemplazarse directamente. Sin embargo, si se requiere compatibilidad binaria hacia atrás, entonces los primeros tres métodos deben abandonarse. Solo el último método con un parámetro de matriz de cadenas es equivalente a la versión variádica, por lo que puede ser reemplazado por la versión variádica.
Tipo de fundición
Si desea que la persona que llama sepa qué tipo de parámetros se deben usar, debe evitar el tipo de fundición con parámetros mutables. Mirando el siguiente ejemplo, la primera esperanza es la cadena, y la segunda esperanza es la excepción:
Log.log (objeto ... objetos) {String Message = (String) Objetos [0]; if (Objects.Length> 1) {Exception e = (Exception) Objects [1]; // Haga algo con la excepción}} La firma del método debe ser la siguiente, y los parámetros mutables correspondientes se declaran utilizando cadena y excepción respectivamente:
La copia del código es la siguiente: log.log (mensaje de cadena, excepción e, objeto ... objetos) {...}
No use parámetros variables para destruir el sistema de tipos. Solo se puede usar cuando se escribe fuertemente. Para esta regla, printstream.printf () es una excepción interesante: proporciona información de tipo como su primer argumento para que esos tipos puedan aceptarse más adelante.
Retorno de covarianza
El uso básico del retorno covariante es evitar el lanzamiento de tipo cuando se sabe que el tipo de retorno de una implementación es más específico que la API. En el siguiente ejemplo, hay una interfaz de zoológico que devuelve un objeto animal. Nuestra implementación devuelve un objeto Animalimpl, pero antes de JDK 1.5, debe declararse para devolver un objeto animal. :
Public Interface Zoo {public animal getAnimal ();} public class ZooImpl implements Zoo {public animal getAnimal () {return new AnimalImpl ();}}El uso de devoluciones covariantes reemplaza tres antipatrones:
Acceso directo al campo. Para eludir las limitaciones de API, algunas implementaciones exponen subclases directamente a los campos:
Copie el código de la siguiente manera: ZooImpl._Animal
Otra forma es realizar una conversión hacia abajo en el programa de llamadas, sabiendo que la implementación es en realidad una subclase específica:
La copia del código es la siguiente: ((AnimalImpl) ZooImpl.GetAnimal ()). Implethod ();
La última forma que he visto es un método concreto que se usa para evitar problemas causados por una firma completamente diferente:
La copia del código es la siguiente: zooImpl._getAnimal ();
Estos tres modos tienen sus problemas y limitaciones. O no es lo suficientemente ordenado o expone detalles de implementación innecesarios.
Covarianza
El modo de retorno covariante es más limpio, más seguro y fácil de mantener, y no requiere un tipo de fundición o métodos o campos específicos:
public animalImpl getAnimal () {return new AnimalImpl (); } Use resultados:
La copia del código es la siguiente: ZooImpl.GetAnimal (). Implethod ();
Usando genéricos
Aprenderemos sobre genéricos desde dos perspectivas: usar genéricos y construir genéricos. No discutimos el uso obvio de la lista, el conjunto y el mapa. Es suficiente saber que las colecciones genéricas son poderosas y deben usarse con frecuencia.
Discutiremos el uso de métodos genéricos y el método del compilador de inferir tipos. Por lo general, ninguno de estos saldrá mal, pero cuando algo sale mal, el mensaje de error puede ser muy confuso, por lo que debe saber cómo solucionar estos problemas.
Métodos genéricos
Además de los tipos genéricos, Java 5 también introduce métodos genéricos. En este ejemplo de java.util.collections, se construye una lista de elementos únicos. El tipo de elemento de la nueva lista se infiere en función del tipo de objeto aprobado en el método:
Copie el código de la siguiente manera: static <t> list <t> collections.singletonList (T o)
Ejemplo de uso:
Lista pública <integer> getListOfNe () {return Collections.singletonList (1);}En el uso de ejemplo, pasamos un int. Entonces, el tipo de retorno del método es la lista <integer>. El compilador infiere t a entero. Esto es diferente de los tipos genéricos, porque generalmente no necesita especificar parámetros de tipo explícitamente.
Esto también muestra la interacción entre autoboxing y genéricos. El parámetro de tipo debe ser un tipo de referencia: es por eso que estamos obteniendo List <Steger> en lugar de List <Sint>.
Métodos genéricos sin parámetros
El método scOwylist () se introduce con genéricos como una permutación segura de tipo de campo en java.util.collections:
Copie el código de la siguiente manera: static <t> list <t> collections.emptylist ()
Ejemplo de uso:
Lista pública <Integer> getNoNteGers () {return Collections.Emptylist ();}A diferencia del ejemplo anterior, este método no tiene parámetros, entonces, ¿cómo infiere el compilador el tipo de T? Básicamente, intentará usar el parámetro una vez. Si no funciona, intenta usar el tipo de devolución o asignación nuevamente. En este ejemplo, la devolución es lista <integer>, por lo que t se infiere como entero.
¿Qué sucede si se llama un método genérico fuera de la declaración de devolución o la declaración de asignación? Entonces el compilador no podrá realizar la segunda transferencia de inferencia de tipo. En el siguiente ejemplo, se llama a Sacylist () desde el interior del operador condicional:
Lista pública <integer> getNoNtegers () {return x? Colección.emptylist (): nulo;} Debido a que el compilador no puede ver el contexto de retorno y no puede inferir T, abandona y toma objeto. Verá un mensaje de error como: "No se puede convertir la lista <ject> a la lista <integer>".
Para corregir este error, los parámetros de tipo deben pasar explícitamente a la llamada del método. De esta manera, el compilador no intentará inferir parámetros de tipo y puede obtener el resultado correcto:
La copia del código es la siguiente: ¿Retorno x? Colecciones. <Integer> vacyList (): nulo;
Otro lugar donde esto sucede a menudo es en llamadas de método. Si un método toma un parámetro de lista <string> y necesita llamar al vacío pasado () para ese parámetro, entonces también se requiere esta sintaxis.
Fuera de la colección
Aquí hay tres ejemplos de tipos genéricos, que no son colecciones, pero usan genéricos de una manera novedosa. Los tres ejemplos provienen de bibliotecas Java estándar:
Copie el código de la siguiente manera: Clase <T>
La clase se parametriza en el tipo de clase. Esto hace posible construir una NewInstance sin el tipo de fundición.
Copie el código de la siguiente manera: comparable <t>
Comparable se parametriza por el tipo de comparación real. Esto proporciona una escritura más fuerte cuando compare () llamadas. Por ejemplo, String implementa comparable <String>. Llamar a Compareto () en cualquier otra cosa que no sea cadena fallará en el momento de la compilación.
Copie el código de la siguiente manera: Enum <e extiende Enum <E>>
Enum es parametrizado por el tipo enum. Un tipo de enumio llamado color se extenderá a Enum <Color>. El método getDeclaringClass () devuelve un objeto de clase de tipo de enumeración, en este ejemplo, un objeto de color. Es diferente de GetClass (), que puede devolver una clase sin nombre.
Comodín
La parte más compleja de los genéricos es la comprensión de los personajes comodín. Discutiremos tres tipos de comodines y sus usos.
Primero comprendamos cómo funcionan las matrices. Puede asignar un valor de un entero [] a un número []. Si intenta escribir un flotador al número [], se puede compilar, pero fallará en tiempo de ejecución y aparece una ArrayStoreException:
Entero [] ia = nuevo entero [5]; número [] na = ia; na [0] = 0.5; // compila, pero falla en tiempo de ejecución
Si intenta convertir el ejemplo directamente en un genérico, fallará en el momento de la compilación porque la tarea no está permitida:
List <Integer> ilist = new ArrayList <Integer> (); List <Number> nlist = ilist; // no permitidonlist.add (0.5);
Si usa Generics, no encontrará una ClassCastException de tiempo de ejecución siempre que el código no aparezca al compilar.
Comodín de límite superior
Lo que queremos es una lista del tipo de elemento exacto desconocido, que es diferente de las matrices.
List <number> es una lista cuyo tipo de elemento es el número de tipo específico.
Lista <? El número de extensiones> es una lista del tipo de elemento exacto desconocido. Es el número o su subtipo.
Límite superior
Si actualizamos el ejemplo inicial y asignamos el valor a la lista <? extiende el número>, entonces la tarea tendrá éxito ahora:
List <Integer> ilist = new ArrayList <Integer> (); List <? extiende número> nlist = ilist; número n = nlist.get (0); nlist.add (0.5); // no permitido
Podemos obtener el número de la lista porque podemos asignarlo al número independientemente del tipo de elemento exacto de la lista (flotante, entero o número).
Todavía no podemos insertar tipos de puntos flotantes en la lista. Esto fallará en el momento de la compilación porque no podemos demostrar que esto sea seguro. Si queremos agregar tipos de puntos flotantes a la lista, romperá la seguridad de tipo inicial de ilist, solo almacena entero.
Los comodines nos dan más poder expresivo que las matrices.
Por qué usar comodines
En el siguiente ejemplo, los comodines se utilizan para ocultar información de tipo de usuarios de la API. Internamente, el conjunto se almacena como CustomerImpl. Los usuarios de la API solo saben que están obteniendo un conjunto del que pueden leer al cliente.
Los comodines se requieren aquí porque es imposible asignar valores para establecer <Customer> de SET <ClectiveImpl>:
clase pública CustomerFactory {set private <scleMeMpl> _customers; set público <? extiende el cliente> getCustomers () {return _customers;}}Comodín y regreso covariante
Otro uso común de los personajes comodín es usarlo con un retorno covariante. Las mismas reglas que la asignación se pueden aplicar a las devoluciones covariantes. Si desea devolver un tipo genérico más específico en un método reescrito, el método declarado debe usar un comodín:
Interfaz pública NumberGenerator {Lista pública <? extiende número> generate ();} public class FibonacCigenerator extiende NumberGenerator {public List <Integer> Generate () {...}}Si desea usar una matriz, la interfaz puede devolver el número [], mientras que la implementación puede devolver el número entero [].
Límite inferior
De lo que estamos hablando es principalmente sobre el comodín del límite superior. También hay un comodín de límite inferior. Lista <? Super Number> es una lista del "tipo de elemento" exacto desconocido, pero puede ser mnumber o el supertipo de número. Por lo tanto, podría ser una lista <numer> o una lista <s objeto>.
Los comodines de baja limitación son mucho menos comunes que los comodines de la alta limitación, pero son necesarios cuando son necesarios.
Límite inferior y superior
Lista <? extiende el número> readList = new ArrayList <Integer> (); número n = readList.get (0); list <? Super Number> WriteList = new ArrayList <ject> (); writeList.Add (nuevo entero (5));
El primero es una lista de números que se pueden leer.
El segundo es una lista de números a los que puede escribir.
Comodín sin ilimitado
Finalmente, el contenido de una lista de la lista puede ser de cualquier tipo, y es casi el mismo que la lista <? extiende objeto>. Los objetos se pueden leer en cualquier momento, pero el contenido no se puede escribir en la lista.
Comodines en API públicas
En resumen, como se mencionó anteriormente, los comodines son muy importantes para ocultar los detalles de implementación de la persona que llama, pero incluso si los comodines de los bordes inferiores parecen proporcionar acceso de solo lectura, no son el caso debido a métodos no genéricos como Remover (INT Position). Si desea una colección verdaderamente sin cambios, puede usar el método en java.util.collection como unmodifiablelist ().
Recuerde los comodines cuando escriba API. En general, al pasar tipos genéricos, debe intentar usar comodines. Permite que más llamadas accedan a la API.
Recibiendo la lista <? extiende el número> En lugar de la lista <número>, el siguiente método puede llamarse por muchos tipos diferentes de listas:
La copia del código es la siguiente: Void RemoVenegative (List <? Extends Number> List);
Construir tipos genéricos
Ahora discutiremos la construcción de nuestros propios tipos genéricos. Mostraremos algunos ejemplos en los que se puede mejorar la seguridad de los tipos mediante el uso de genéricos, y también discutiremos algunos problemas comunes al implementar tipos genéricos.
Funciones similares a la colección
El primer ejemplo de una clase genérica es un ejemplo de estilo de colección. El par tiene dos parámetros de tipo, y el campo es una instancia de tipo:
Public final de la clase par <a, b> {public Final A First; Public Final B Second; Public Par (A First, B Segundo) {this.first = First; this.Second = Second;}}Esto permite devolver dos elementos de un método sin escribir una clase dedicada para cada combinación de dos tipos. Otra forma es devolver el objeto [], que es el tipo no seguro o desordenado.
En el siguiente uso, devolvemos un archivo y un booleano del método. El cliente del método puede usar campos directamente sin el tipo de fundición:
Public Par <File, Boolean> getFileAndWriteStatus (string path) {// Crear archivo y statusreturn nuevo par <file, boolean> (archivo, status);} par <archivo, boolean> result = getFileAndWriteStatus ("..."); file f = result.first; boolean escritable = resultado.second;Fuera de la colección
En el siguiente ejemplo, los genéricos se utilizan para la seguridad adicional del tiempo de compilación. Al parametrizar la clase DBFactory al tipo de par de pares creado, en realidad está obligando a la subclase de fábrica a devolver un subtipo específico de un par:
Public Abstract Class dbFactory <t extiende dbpeer> {protegido abstracto t createEmptypeer (); public List <T> get (restricción de cadena) {list <t> peers = new ArrayList <T> (); // Base de datos MagicReturn Peers;}}Al implementar DBFactory <Customer>, CustomerFactory debe devolver a un cliente de CreateEmptypeer ()::
Public Class CustomerFactory extiende DBFactory <Customer> {public Customer createEmptypeer () {return new Customer ();}}Métodos genéricos
Ya sea que desee imponer restricciones a los tipos genéricos entre parámetros y entre parámetros y tipos de retorno, puede usar métodos genéricos:
Por ejemplo, si la función de inversión escrita está invertida posicionalmente, entonces no se requiere un método genérico. Sin embargo, si desea que la inversión devuelva una nueva lista, es posible que desee que el tipo de elemento de la nueva lista sea el mismo que el tipo de la lista entrante. En este caso, se necesita un método genérico:
Copie el código de la siguiente manera: <t> List <T> Reverse (List <T> List)
Concreto
Al implementar una clase genérica, es posible que desee construir una matriz t []. Debido a que los genéricos son implementados por borrado, esto no está permitido.
Puedes intentar lanzar objeto [] a t []. Pero esto no es seguro.
Soluciones concretas
Según la convención de tutoriales genéricos, la solución utiliza un "token tipo". Al agregar un parámetro de clase <t> al constructor, puede obligar al cliente a proporcionar el objeto de clase correcto para los parámetros de tipo de clase:
public class arrayExample <t> {private clase <t> clazz; public arrayExample (clase <t> clazz) {this.clazz = clazz;} public t [] getArray (int size) {return (t []) array.newinstance (clazz, size);}}Para construir un arrayExample <String>, el cliente debe pasar String.class al constructor porque el tipo de string.class es clase <string>.
Tener un objeto de clase permite construir un grupo de un tipo de elemento correcto
Espero que este artículo sea útil para la programación Java de todos.