stringtranslate.com

sintaxis de java

Un fragmento de código Java con palabras clave resaltadas en negrita azul

La sintaxis de Java es el conjunto de reglas que definen cómo se escribe e interpreta un programa Java .

La sintaxis se deriva principalmente de C y C++ . A diferencia de C++, en Java no hay funciones o variables globales, pero hay miembros de datos que también se consideran variables globales . Todo el código pertenece a clases y todos los valores son objetos . La única excepción son los tipos primitivos , que no están representados por una instancia de clase por razones de rendimiento (aunque se pueden convertir automáticamente en objetos y viceversa mediante autoboxing). Algunas características como la sobrecarga de operadores o los tipos de enteros sin signo se omiten para simplificar el lenguaje y evitar posibles errores de programación.

La sintaxis de Java se ha ampliado gradualmente a lo largo de numerosas versiones importantes de JDK y ahora admite capacidades como programación genérica y literales de funciones (llamadas expresiones lambda en Java). Desde 2017, se lanza una nueva versión de JDK dos veces al año, y cada versión aporta mejoras incrementales al lenguaje.

Lo esencial

Identificador

Un identificador es el nombre de un elemento en el código . Existen ciertas convenciones de nomenclatura estándar que se deben seguir al seleccionar nombres para elementos. Los identificadores en Java distinguen entre mayúsculas y minúsculas .

Un identificador puede contener:

Un identificador no puede:

Palabras clave

Literales

Los literales enteros son de inttipo por defecto a menos que longel tipo se especifique añadiendo Lo lsufijo al literal, por ejemplo 367L. Desde Java SE 7, es posible incluir guiones bajos entre los dígitos de un número para aumentar la legibilidad; por ejemplo, un número 145608987 se puede escribir como 145_608_987 .

variables

Las variables son identificadores asociados con valores. Se declaran escribiendo el tipo y el nombre de la variable y, opcionalmente, se inicializan en la misma declaración asignando un valor.

recuento int ; //Declarando una variable no inicializada llamada 'count', de tipo 'int' count = 35 ; //Inicializando la variable int count = 35 ; //Declarando e inicializando la variable al mismo tiempo         

Se pueden declarar e inicializar múltiples variables del mismo tipo en una declaración usando una coma como delimitador.

ent a , b ; //Declarando múltiples variables del mismo tipo int a = 2 , b = 3 ; //Declarando e inicializando múltiples variables del mismo tipo          

Inferencia de tipos

Desde Java 10, es posible inferir tipos de variables automáticamente mediante el uso de var.

// la secuencia tendrá el tipo FileOutputStream como se infiere de su inicializador var stream = new FileOutputStream ( "file.txt" );    // Una declaración equivalente con un tipo explícito FileOutputStream stream = new FileOutputStream ( "file.txt" );    

Bloques de código

Los separadores { y } significan un bloque de código y un nuevo alcance. Los miembros de la clase y el cuerpo de un método son ejemplos de lo que puede vivir dentro de estas llaves en diversos contextos.

Dentro de los cuerpos de los métodos, se pueden usar llaves para crear nuevos alcances, de la siguiente manera:

void hacer algo () { int a ;     { intb ;un = 1 ; }       a = 2 ; segundo = 3 ; // Ilegal porque la variable b está declarada en un ámbito interno.. }      

Comentarios

Java tiene tres tipos de comentarios : comentarios tradicionales , comentarios de final de línea y comentarios de documentación .

Los comentarios tradicionales, también conocidos como comentarios de bloque, comienzan con /*y terminan con */y pueden abarcar varias líneas. Este tipo de comentario se derivó de C y C++.

/* Este es un comentario de varias líneas. Puede ocupar más de una línea. */

Los comentarios de final de línea comienzan //y se extienden hasta el final de la línea actual. Este tipo de comentario también está presente en C++ y en el C moderno.

// Este es un comentario de final de línea

La herramienta Javadoc procesa los comentarios de la documentación en los archivos fuente para generar documentación. Este tipo de comentario es idéntico a los comentarios tradicionales, excepto que comienza /**y sigue las convenciones definidas por la herramienta Javadoc. Técnicamente, estos comentarios son un tipo especial de comentario tradicional y no están definidos específicamente en la especificación del lenguaje.

/** * Este es un comentario de documentación. * * @autor John Doe */

Tipos universales

Las clases del paquete java.lang se importan implícitamente a cada programa, siempre que ningún tipo importado explícitamente tenga los mismos nombres. Los importantes incluyen:

java.lang.Objeto

java.lang.Objectes el tipo superior de Java . Superclase de todas las clases que no declaran una clase padre. Todos los valores se pueden convertir a este tipo, aunque para los valores primitivos esto implica autoboxing .

java.lang.String

java.lang.Stringes el tipo de cadena básico de Java. Inmutable . Algunos métodos tratan cada unidad de código UTF-16 como un "carácter", pero también están disponibles métodos para convertir a un int[]código que sea efectivamente UTF-32 .

java.lang.Throwable

java.lang.Throwablees un supertipo de todo lo que se puede lanzar o capturarthrow con declaraciones and de Java catch.

Estructura del programa

Las aplicaciones Java constan de colecciones de clases. Las clases existen en paquetes pero también se pueden anidar dentro de otras clases.

mainmétodo

Cada aplicación Java debe tener un punto de entrada. Esto se aplica tanto a las aplicaciones de interfaz gráfica como a las aplicaciones de consola. El punto de entrada es el mainmétodo. Puede haber más de una clase con un mainmétodo, pero la clase principal siempre se define externamente (por ejemplo, en un archivo de manifiesto ). mainSe debe declarar el método junto con la clase principal public. El método debe ser staticy se le pasan argumentos de línea de comandos como una matriz de cadenas. A diferencia de C++ o C# , nunca devuelve un valor y debe devolverlo void.

público estático vacío principal ( String [] args ) { }     

Paquetes

Los paquetes son parte del nombre de una clase y se utilizan para agrupar y/o distinguir entidades nombradas de otras. Otro propósito de los paquetes es gobernar el acceso al código junto con los modificadores de acceso. Por ejemplo, java.io.InputStreames un nombre de clase completo para la clase InputStreamque se encuentra en el paquete java.io.

Se declara un paquete al comienzo del archivo con la packagedeclaración:

paquete miaplicación.mibiblioteca ; clase pública MiClase { }   

Las clases con el publicmodificador deben colocarse en archivos con el mismo nombre y extensión de Java y colocarse en carpetas anidadas correspondientes al nombre del paquete. La clase anterior tendrá la siguiente ruta: .myapplication.mylibrary.MyClassmyapplication/mylibrary/MyClass.java

Declaración de importación

Tipo declaración de importación

Una declaración de importación de tipos permite hacer referencia a un tipo con nombre mediante un nombre simple en lugar del nombre completo que incluye el paquete. Las declaraciones de importación pueden ser declaraciones de importación de tipo único o declaraciones de importación bajo demanda . Las declaraciones de importación deben colocarse en la parte superior de un archivo de código después de la declaración del paquete.

paquete miPaquete ; importar java.util.Random ; // Declaración de tipo único  public class ImportsTest { public static void main ( String [] args ) { /* La siguiente línea es equivalente a  * java.util.Random random = new java.util.Random();  * Habría sido incorrecto sin la importación.  */ Aleatorio aleatorio = nuevo Aleatorio (); } }                

Las declaraciones de importación bajo demanda se mencionan en el código. Una "importación de tipo" importa todos los tipos del paquete. Una "importación estática" importa miembros del paquete.

importar java.util.* ; /*Esta forma de importar clases hace que todas las clases  del paquete java.util estén disponibles por nombre; podría usarse en lugar de la  declaración de importación del ejemplo anterior. */ importar java.* ; /*Esta declaración es legal, pero no hace nada, ya que  no hay clases directamente en el paquete java. Todos ellos están en paquetes  dentro del paquete java. Esto no importa todas las clases disponibles.*/    

Declaración de importación estática

Este tipo de declaración está disponible desde J2SE 5.0 . Las declaraciones de importación estáticas permiten el acceso a miembros estáticos definidos en otra clase, interfaz, anotación o enumeración; sin especificar el nombre de la clase:

importar java.lang.System.out estático ; //'out' es un campo estático en java.lang.System  public class HolaMundo { public static void main ( String [] args ) { /* La siguiente línea es equivalente a  System.out.println("¡Hola mundo!");  y habría sido incorrecto sin la declaración de importación. */ afuera . println ( "¡Hola mundo!" ); } }            

Las declaraciones de importación bajo demanda permiten importar todos los campos del tipo:

importar java.lang.System.* estático ; /* Esta forma de declaración hace que todos  los campos de la clase java.lang.System estén disponibles por nombre y puede usarse en lugar  de la declaración de importación del ejemplo anterior. */  

Las constantes de enumeración también se pueden utilizar con importación estática. Por ejemplo, esta enumeración está en el paquete llamado screen:

enumeración pública ColorName { ROJO , AZUL , VERDE };      

Es posible utilizar declaraciones de importación estáticas en otra clase para recuperar las constantes de enumeración:

importar pantalla.ColorName ; importar pantalla estática.ColorName.* ;  public class Dots { /* La siguiente línea es equivalente a 'ColorName foo = ColorName.RED'  y habría sido incorrecta sin la importación estática. */ ColorName foo = ROJO ;         void shift () { /* La siguiente línea es equivalente a  if (foo == ColorName.RED) foo = ColorName.BLUE; */ if ( foo == ROJO ) foo = AZUL ; } }           

Operadores

Los operadores en Java son similares a los de C++ . Sin embargo, no hay ningún deleteoperador debido a los mecanismos de recolección de basura en Java y no hay operaciones con punteros ya que Java no los admite. Otra diferencia es que Java tiene un operador de desplazamiento a la derecha sin signo ( >>>), mientras que la firma del operador de desplazamiento a la derecha de C depende del tipo. Los operadores en Java no se pueden sobrecargar .

Estructuras de Control

Declaraciones condicionales

ifdeclaración

si las declaraciones en Java son similares a las de C y usan la misma sintaxis:

si ( i == 3 ) { hacer algo (); }     

ifLa declaración puede incluir elseun bloque opcional, en cuyo caso se convierte en una declaración if-then-else:

si ( i == 3 ) { hacer algo (); } más { hacer algo más (); }        

Al igual que C, la construcción else-if no implica ninguna palabra clave especial, se forma como una secuencia de declaraciones separadas if-then-else:

si ( i == 3 ) { hacer algo (); } más si ( i == 2 ) { hacer algo más (); } más { hacer algo diferente (); }               

Además, tenga en cuenta que el operador ?: se puede utilizar en lugar de una simple declaración if, por ejemplo

int a = 1 ; int b = 2 ; int valormínimo = ( a < b ) ? a : b ;               

switchdeclaración

Las declaraciones de cambio en Java pueden usar tipos de datos primitivos byte, short, chary int(nota: no long) o sus tipos de contenedor correspondientes. A partir de J2SE 5.0, es posible utilizar tipos de enumeración . A partir de Java SE 7, es posible utilizar cadenas. [2] No se pueden utilizar otros tipos de referenciaswitch en las declaraciones.

Los valores posibles se enumeran mediante caseetiquetas. Estas etiquetas en Java pueden contener solo constantes (incluidas constantes de enumeración y constantes de cadena). La ejecución comenzará después de la etiqueta correspondiente a la expresión dentro de los corchetes. Puede haber una etiqueta opcional defaultpara declarar que el código que le sigue se ejecutará si ninguna de las etiquetas de caso corresponde a la expresión.

El código de cada etiqueta termina con la breakpalabra clave. Es posible omitirlo, lo que hace que la ejecución pase a la siguiente etiqueta; sin embargo, normalmente se informará una advertencia durante la compilación.

cambiar ( ch ) { caso 'A' : hacer algo (); // Activado si ch == 'A' break ; caso 'B' : caso 'C' : hacer algo más (); // Se activa si ch == 'B' o ch == 'C' se rompen ; predeterminado : hacer algo diferente (); // Activado en cualquier otro caso break ; }                  
switchexpresiones

Desde Java 14, es posible utilizar expresiones de cambio, que utilizan la nueva sintaxis de flecha:

var resultado = cambiar ( ch ) { caso 'A' -> Resultado . EXCELENTE ; caso 'B' , 'C' -> Resultado . BIEN ; predeterminado -> lanzar nueva ThisIsNoGoodException (); };                   

Alternativamente, existe la posibilidad de expresar lo mismo con la yielddeclaración, aunque se recomienda preferir la sintaxis de flecha porque evita el problema de caídas accidentales.

var resultado = switch ( ch ) { case 'A' : produce resultado . EXCELENTE ; caso 'B' : caso 'C' : rendimiento Resultado . BIEN ; predeterminado : lanzar nueva ThisIsNoGoodException (); };                   

Declaraciones de iteración

Las declaraciones de iteración son declaraciones que se ejecutan repetidamente cuando una condición determinada se evalúa como verdadera. Desde J2SE 5.0 , Java tiene cuatro formas de declaraciones de este tipo. Tenga en cuenta que la condición debe ser de tipo booleano o booleano, es decir, C.

mientras ( 1 ) { hacer algo (); }   

produce un error de compilación.

whilebucle

En el whilebucle, la prueba se realiza antes de cada iteración.

mientras ( i < 10 ) { hacer algo (); }     

do ... whilebucle

En el do ... whilebucle, la prueba se realiza después de cada iteración. En consecuencia, el código siempre se ejecuta al menos una vez.

// doSomething() se llama al menos una vez do { doSomething (); } mientras ( yo < 10 );      

forbucle

forLos bucles en Java incluyen un inicializador, una condición y una expresión de contador. Es posible incluir varias expresiones del mismo tipo utilizando la coma como delimitador (excepto en la condición). Sin embargo, a diferencia de C, la coma es sólo un delimitador y no un operador.

for ( int i = 0 ; i < 10 ; i ++ ) { hacer algo (); } // Un bucle más complejo que usa dos variables for ( int i = 0 , j = 9 ; i < 10 ; i ++ , j -= 3 ) { doSomething (); }                           

Al igual que C, las tres expresiones son opcionales. El siguiente bucle es infinito:

para (;;) { hacer algo (); }   

forBucle mejorado

forLos bucles mejorados están disponibles desde J2SE 5.0 . Este tipo de bucle utiliza iteradores integrados sobre matrices y colecciones para devolver cada elemento de la colección determinada. Cada elemento se devuelve y es accesible en el contexto del bloque de código. Cuando se ejecuta el bloque, se devuelve el siguiente elemento hasta que no queden elementos. A diferencia de C# , este tipo de bucle no implica una palabra clave especial, sino que utiliza un estilo de notación diferente.

for ( int i : intArray ) { hacer algo ( i ); }      

Declaraciones de salto

Etiquetas

Las etiquetas reciben puntos en el código utilizado por breaky continuedeclaraciones. Tenga en cuenta que la palabra clave Java gotono se puede utilizar para saltar a puntos específicos del código.

inicio : algún método ();

breakdeclaración

La breakdeclaración sale del bucle o switchdeclaración más cercana. La ejecución continúa en la declaración después de la declaración terminada, si corresponde.

for ( int i = 0 ; i < 10 ; i ++ ) { while ( true ) { break ; } // Llegará a este punto }               

Es posible salir del bucle exterior utilizando etiquetas:

exterior : for ( int i = 0 ; i < 10 ; i ++ ) { while ( true ) { break exterior ; } } // Se romperá hasta este punto               

continuedeclaración

La continuedeclaración interrumpe la iteración actual de la declaración de control actual y comienza la siguiente iteración. El siguiente whilebucle en el código siguiente lee los caracteres llamando a getChar(), omitiendo las declaraciones en el cuerpo del bucle si los caracteres son espacios:

int ch ; mientras ( ch == getChar ()) { si ( ch == ' ' ) { continuar ; // Salta el resto del ciclo while }              // El resto del bucle while no se alcanzará si ch == ' ' doSomething (); } 

Las etiquetas se pueden especificar en continuedeclaraciones y breakdeclaraciones:

exterior : para ( String str : stringsArr ) { char [] strChars = str . toCharArray (); for ( char ch : strChars ) { if ( ch == ' ' ) { /* Continúa el ciclo externo y la siguiente  cadena se recupera de stringsArr */ continue external ; } hacer algo ( ch ); } }                          

returndeclaración

La returndeclaración se utiliza para finalizar la ejecución del método y devolver un valor. Un valor devuelto por el método se escribe después de la returnpalabra clave. Si el método devuelve cualquier cosa menos void, debe usar la returndeclaración para devolver algún valor.

void doSomething ( boolean streamClosed ) { // Si streamClosed es verdadero, la ejecución se detiene if ( streamClosed ) { return ; } leerDesdeStream (); }          int calcularSuma ( int a , int b ) { int resultado = a + b ; resultado de retorno ; }             

returnLa declaración finaliza la ejecución inmediatamente, excepto en un caso: si la declaración se encuentra dentro de un trybloque y se complementa con un finally, el control se pasa al finallybloque.

void hacer algo ( boolean streamClosed ) { intentar { if ( streamClosed ) { return ; } leerDesdeStream (); } finalmente { /* Se llamará en último lugar incluso si  no se llamó a readFromStream() */ freeResources (); } }                 

Declaraciones de manejo de excepciones

try-catch-finallydeclaraciones

Las excepciones se gestionan dentro de try... catchbloques.

try { // Declaraciones que pueden generar excepciones métodoThrowingExceptions (); } catch ( Exception ex ) { // Excepción detectada y manejada aquí reportException ( ex ); } finalmente { // Las declaraciones siempre se ejecutan después de los bloques try/catch freeResources (); }             

Las declaraciones dentro del trybloque se ejecutan y, si alguna de ellas genera una excepción, la ejecución del bloque se interrumpe y el bloque maneja la excepción catch. Puede haber varios catchbloques, en cuyo caso se ejecuta el primer bloque con una variable de excepción cuyo tipo coincida con el tipo de excepción lanzada.

Java SE 7 también introdujo cláusulas multi-catch además de cláusulas uni-catch. Este tipo de cláusulas catch permite a Java manejar diferentes tipos de excepciones en un solo bloque siempre que no sean subclases entre sí.

prueba { métodoThrowingExceptions (); } catch ( IOException | IllegalArgumentException ex ) { // Tanto IOException como IllegalArgumentException serán capturados y manejados aquí reportException ( ex ); }          

Si ningún catchbloque coincide con el tipo de excepción lanzada, la ejecución del bloque externo (o método) que contiene la instrucción try... catchse interrumpe y la excepción se pasa hacia arriba y fuera del bloque (o método) que lo contiene. La excepción se propaga hacia arriba a través de la pila de llamadas hasta que se encuentra un catchbloque coincidente dentro de uno de los métodos actualmente activos. Si la excepción se propaga hasta el método superior sin que se encuentre mainun bloque coincidente , se escribe una descripción textual de la excepción en el flujo de salida estándar.catch

Las declaraciones dentro del finallybloque siempre se ejecutan después de los bloques tryy catch, independientemente de si se lanzó o no una excepción e incluso si returnse alcanzó una declaración. Estos bloques son útiles para proporcionar código de limpieza que se garantiza que siempre se ejecutará.

Los bloques catchy finallyson opcionales, pero al menos uno u otro debe estar presente después del trybloque.

try-declaraciones con recursos

tryLas declaraciones -with-resources son un tipo especial de try-catch-finallydeclaraciones introducidas como una implementación del patrón de disposición en Java SE 7. En una trydeclaración -with-resources, la trypalabra clave va seguida de la inicialización de uno o más recursos que se liberan automáticamente cuando se ejecuta el trybloque. Está terminado. Los recursos deben implementarse java.lang.AutoCloseable. try-No es necesario que las declaraciones with-resources tengan un bloque catcho finallya diferencia de las declaraciones normales try-catch-finally.

try ( FileOutputStream fos = nuevo FileOutputStream ( "nombre de archivo" ); XMLEncoder xEnc = nuevo XMLEncoder ( fos )) { xEnc . escribirObjeto ( objeto ); } catch ( IOException ex ) { Registrador . getLogger ( Serializador . Clase . getName ()). log ( Nivel . SEVERO , nulo , ex ); }                   

Desde Java 9 es posible utilizar variables ya declaradas:

FileOutputStream fos = nuevo FileOutputStream ( "nombre de archivo" ); XMLEncoder xEnc = nuevo XMLEncoder ( fos ); intentar ( fos ; xEnc ) { xEnc . escribirObjeto ( objeto ); } catch ( IOException ex ) { Registrador . getLogger ( Serializador . Clase . getName ()). log ( Nivel . SEVERO , nulo , ex ); }                   

throwdeclaración

La throwdeclaración se utiliza para lanzar una excepción y finalizar la ejecución del bloque o método. La instancia de excepción lanzada se escribe después de la throwdeclaración.

método voidThrowingExceptions ( Objeto obj ) { if ( obj == null ) { // Lanza una excepción de tipo NullPointerException throw new NullPointerException (); } // No será llamado, si el objeto es nulo doSomethingWithObject ( obj ); }               

Control de concurrencia de subprocesos

Java tiene herramientas integradas para programación multiproceso . A los efectos de la sincronización de subprocesos, la synchronizeddeclaración se incluye en lenguaje Java.

Para sincronizar un bloque de código, va precedido de la synchronizedpalabra clave seguida del objeto de bloqueo entre corchetes. Cuando el subproceso en ejecución alcanza el bloque sincronizado, adquiere un bloqueo de exclusión mutua , ejecuta el bloque y luego libera el bloqueo. Ningún hilo puede ingresar a este bloque hasta que se libere el bloqueo. Se puede utilizar cualquier tipo de referencia que no sea nulo como bloqueo.

/* Adquiere el bloqueo sobre algún Objeto. Debe ser de un tipo de referencia y no debe ser nulo */ sincronizado ( algúnObjeto ) { // Declaraciones sincronizadas }   

assertdeclaración

assertLas declaraciones han estado disponibles desde J2SE 1.4 . Estos tipos de declaraciones se utilizan para realizar afirmaciones en el código fuente, que se pueden activar y desactivar durante la ejecución de clases o paquetes específicos. Para declarar una aserción assertse utiliza la palabra clave seguida de una expresión condicional. Si se evalúa hasta falseel momento en que se ejecuta la declaración, se lanza una excepción. Esta declaración puede incluir dos puntos seguidos de otra expresión, que actuará como mensaje detallado de la excepción.

// Si n es igual a 0, se lanza AssertionError afirmar n != 0 ; /* Si n es igual a 0, se generará AssertionError con el mensaje después de los dos puntos */ afirmar n != 0 : "n fue igual a cero" ;        

tipos primitivos

Los tipos primitivos en Java incluyen tipos enteros, números de punto flotante, unidades de código UTF-16 y un tipo booleano. No hay tipos sin firmar en Java excepto charel tipo, que se utiliza para representar unidades de código UTF-16. La falta de tipos sin signo se compensa mediante la introducción de la operación de desplazamiento a la derecha sin signo ( >>>), que no está presente en C++. Sin embargo, se han criticado la falta de compatibilidad que esto provoca con C y C++. [3]

charno necesariamente corresponde a un solo carácter. Puede representar una parte de un par sustituto , en cuyo caso el punto de código Unicode está representado por una secuencia de dos charvalores.

Boxeo y unboxing

Esta característica del lenguaje se introdujo en J2SE 5.0 . El boxeo es la operación de convertir un valor de un tipo primitivo en un valor de un tipo de referencia correspondiente, que sirve como envoltorio para este tipo primitivo en particular. Unboxing es la operación inversa de convertir un valor de un tipo de referencia (previamente encuadrado) en un valor de un tipo primitivo correspondiente. Ninguna operación requiere una conversión explícita.

Ejemplo:

intfoo = 42 ;// Tipo primitivo Barra entera = foo ; /* foo está encuadrado en bar, bar es de tipo entero,  que sirve como contenedor para int */ int foo2 = bar ; // Sin caja y de vuelta al tipo primitivo            

Tipos de referencia

Los tipos de referencia incluyen tipos de clase, tipos de interfaz y tipos de matriz. Cuando se llama al constructor, se crea un objeto en el montón y se asigna una referencia a la variable. Cuando una variable de un objeto sale del alcance, la referencia se rompe y cuando no quedan referencias, el objeto se marca como basura. Luego, el recolector de basura la recoge y la destruye algún tiempo después.

Una variable de referencia es nullcuando no hace referencia a ningún objeto.

matrices

Las matrices en Java se crean en tiempo de ejecución, al igual que las instancias de clase. La longitud de la matriz se define en el momento de la creación y no se puede cambiar.

int [] números = nuevo int [ 5 ] ; números [ 0 ] = 2 ; números [ 1 ] = 5 ; int x = números [ 0 ] ;           

Inicializadores

// Sintaxis larga int [] números = new int [] { 20 , 1 , 42 , 15 , 34 }; // Sintaxis corta int [] números2 = { 20 , 1 , 42 , 15 , 34 };                

Matrices multidimensionales

En Java, las matrices multidimensionales se representan como matrices de matrices. Técnicamente, están representados por matrices de referencias a otras matrices.

int [][] números = nuevo int [ 3 ] [ 3 ] ; números [ 1 ][ 2 ] = 2 ;      int [][] números2 = {{ 2 , 3 , 2 }, { 1 , 2 , 6 }, { 2 , 4 , 5 }};           

Debido a la naturaleza de las matrices multidimensionales, las submatrices pueden variar en longitud, por lo que las matrices multidimensionales no necesariamente son rectangulares a diferencia de C:

int [][] números = nuevo int [ 2 ][] ; //Inicialización solo de la primera dimensión     números [ 0 ] = nuevo int [ 3 ] ; números [ 1 ] = nuevo int [ 2 ] ;      

Clases

Las clases son fundamentos de un lenguaje orientado a objetos como Java. Contienen miembros que almacenan y manipulan datos. Las clases se dividen en de nivel superior y anidadas . Las clases anidadas son clases ubicadas dentro de otra clase que pueden acceder a los miembros privados de la clase adjunta. Las clases anidadas incluyen clases miembro (que pueden definirse con el modificador estático para anidamiento simple o sin él para clases internas), clases locales y clases anónimas .

Declaración

Creación de instancias

Los miembros no estáticos de una clase definen los tipos de variables y métodos de instancia, que están relacionados con los objetos creados a partir de esa clase. Para crear estos objetos, se debe crear una instancia de la clase utilizando el newoperador y llamando al constructor de la clase.

Foo foo = nuevo Foo ();    

Accediendo a miembros

Se accede a los miembros tanto de instancias como de clases estáticas con el .operador (punto).

Acceder a un miembro de la instancia
Se puede acceder a los miembros de la instancia a través del nombre de una variable.

Cadena foo = "Hola" ; Barra de cuerda = foo . aUpperCase ();      

Acceder a un miembro de clase estática
Se accede a los miembros estáticos utilizando el nombre de la clase o cualquier otro tipo. Esto no requiere la creación de una instancia de clase. Los miembros estáticos se declaran utilizando el staticmodificador.

clase pública Foo { public static void hacer algo () { } }         // Llamando al método estático Foo . hacer algo ();

Modificadores

Los modificadores son palabras clave que se utilizan para modificar declaraciones de tipos y miembros de tipo. En particular, hay un subgrupo que contiene los modificadores de acceso.

Clase abstracta

De forma predeterminada, todos los métodos de todas las clases son concretos, a menos que se utilice la palabra clave abstracta. Una clase abstracta puede incluir métodos abstractos que no tienen implementación. De forma predeterminada, todos los métodos en todas las interfaces son abstractos, a menos que se utilice la palabra clave predeterminada. La palabra clave predeterminada se puede utilizar para especificar un método concreto en una interfaz.

// De forma predeterminada, todos los métodos de todas las clases son concretos, a menos que se utilice la palabra clave abstracta. public abstract class Demo { // Una clase abstracta puede incluir métodos abstractos, que no tienen implementación. resumen público int suma ( int x , int y );             // Una clase abstracta también puede incluir métodos concretos. público int producto ( int x , int y ) { return x * y ; } }            // De forma predeterminada, todos los métodos en todas las interfaces son abstractos, a menos que se utilice la palabra clave predeterminada. interfaz  DemoInterface { int getLength (); //La palabra clave abstracta se puede usar aquí, aunque es completamente inútil //La palabra clave predeterminada se puede usar en este contexto para especificar un método concreto en una interfaz default int product ( int x , int y ) { return x * y ; } }                  
clase final

Una clase final no puede subclasificarse. Como hacer esto puede conferir beneficios de seguridad y eficiencia, muchas de las clases de la biblioteca estándar de Java son finales, como java.lang.Systemy java.lang.String.

Ejemplo:

clase final pública MyFinalClass {...}    clase pública ThisIsWrong extiende MyFinalClass {...} // prohibido      
Modificadores de acceso

Los modificadores de acceso , o modificadores de herencia , establecen la accesibilidad de clases, métodos y otros miembros. publicSe puede contactar a los miembros marcados como desde cualquier lugar. Si una clase o su miembro no tiene ningún modificador, se asume el acceso predeterminado.

clase pública Foo { int go () { retorno 0 ; }          Barra de clase privada { } }    

La siguiente tabla muestra si el código dentro de una clase tiene acceso a la clase o método dependiendo de la ubicación de la clase de acceso y el modificador de la clase o miembro de la clase a la que se accede:

Esta imagen describe el alcance del miembro de clase dentro de clases y paquetes.

Constructores e inicializadores

Un constructor es un método especial llamado cuando se inicializa un objeto. Su propósito es inicializar los miembros del objeto. La principal diferencia entre los constructores y los métodos ordinarios es que los constructores se llaman sólo cuando se crea una instancia de la clase y nunca devuelven nada. Los constructores se declaran como métodos comunes, pero reciben el nombre de la clase y no se especifica ningún tipo de retorno:

clase  Foo { cadena cadena ;    Foo () { // Constructor sin argumentos   // Inicialización }  Foo ( String str ) { // Constructor con un argumento this . cadena = cadena ; } }       

Los inicializadores son bloques de código que se ejecutan cuando se crea una clase o una instancia de una clase. Hay dos tipos de inicializadores: inicializadores estáticos e inicializadores de instancia .

Los inicializadores estáticos inicializan los campos estáticos cuando se crea la clase. Se declaran utilizando la staticpalabra clave:

clase  Foo { estático { // Inicialización } }     

Una clase se crea sólo una vez. Por lo tanto, los inicializadores estáticos no se llaman más de una vez. Por el contrario, los inicializadores de instancia se llaman automáticamente antes de llamar a un constructor cada vez que se crea una instancia de la clase. A diferencia de los constructores, los inicializadores de instancias no pueden aceptar ningún argumento y, en general, no pueden generar ninguna excepción marcada (excepto en varios casos especiales). Los inicializadores de instancia se declaran en un bloque sin palabras clave:

clase  Foo { { // Inicialización } }    

Dado que Java tiene un mecanismo de recolección de basura, no hay destructores . Sin embargo, cada objeto tiene un finalize()método llamado antes de la recolección de basura, que puede anularse para implementar la finalización.

Métodos

Todas las declaraciones en Java deben residir dentro de métodos. Los métodos son similares a las funciones excepto que pertenecen a clases. Un método tiene un valor de retorno, un nombre y generalmente algunos parámetros inicializados cuando se llama con algunos argumentos. Al igual que en C++, los métodos que no devuelven nada tienen el tipo de retorno declarado como void. A diferencia de C++, a los métodos en Java no se les permite tener valores de argumento predeterminados y, en su lugar, los métodos suelen estar sobrecargados.

clase  Foo { int bar ( int a , int b ) { return ( a * 2 ) + b ; }             /* Método sobrecargado con el mismo nombre pero diferente conjunto de argumentos */ int bar ( int a ) { return a * 2 ; } }       

Un método se llama usando .notación sobre un objeto, o en el caso de un método estático, también sobre el nombre de una clase.

Foo foo = nuevo Foo (); resultado int = foo . barra ( 7 , 2 ); // Se llama al método no estático en foo         int resultado final = Matemáticas . abdominales ( resultado ); // Llamada a método estático    

La throwspalabra clave indica que un método genera una excepción. Todas las excepciones marcadas deben aparecer en una lista separada por comas.

void openStream () lanza IOException , myException { // Indica que se puede lanzar IOException }      
Modificadores
Métodos finales

Las subclases no pueden anular ni ocultar un método final . [5] Esto se utiliza para evitar un comportamiento inesperado de una subclase que altere un método que puede ser crucial para la función o la coherencia de la clase. [6]

Ejemplo:

base de clase pública { public void m1 () {...} public final void m2 () {...}            public static void m3 () {...} public static final void m4 () {...} }          clase pública Derivada extiende Base { public void m1 () {...} // OK, anulando Base#m1() public void m2 () {...} // prohibido               public static void m3 () {...} // OK, ocultando Base#m3() public static void m4 () {...} // prohibido }           

Un error común es pensar que declarar un método finalmejora la eficiencia al permitir que el compilador inserte directamente el método dondequiera que se llame (ver expansión en línea ). Debido a que el método se carga en tiempo de ejecución , los compiladores no pueden hacer esto. Solo el entorno de ejecución y el compilador JIT saben exactamente qué clases se han cargado y, por lo tanto, solo ellos pueden tomar decisiones sobre cuándo alinear, si el método es final o no. [7]

Los compiladores de código de máquina que generan código de máquina directamente ejecutable y específico de la plataforma son una excepción. Cuando se utilizan enlaces estáticos , el compilador puede asumir con seguridad que los métodos y variables computables en tiempo de compilación pueden estar integrados.
Varargs

Esta característica del lenguaje se introdujo en J2SE 5.0 . El último argumento del método puede declararse como un parámetro de aridad variable, en cuyo caso el método se convierte en un método de aridad variable (a diferencia de los métodos de aridad fija) o simplemente en un método varargs . Esto permite pasar un número variable de valores, del tipo declarado, al método como parámetros, sin incluir parámetros. Estos valores estarán disponibles dentro del método como una matriz.

void printReport ( encabezado de cadena , int ... números ) { //los números representan varargs System . afuera . imprimirln ( encabezado ); for ( int num : números ) { System . afuera . println ( núm ); } }               // Llamando al método varargs printReport ( "Datos del informe" , 74 , 83 , 25 , 96 );    

Campos

Los campos, o variables de clase , se pueden declarar dentro del cuerpo de la clase para almacenar datos.

clase  Foo { doble barra ; }   

Los campos se pueden inicializar directamente cuando se declaran.

clase  Foo { doble barra = 2,3 ; }     
Modificadores

Herencia

Las clases en Java sólo pueden heredar de una clase. Una clase puede derivarse de cualquier clase que no esté marcada como final. La herencia se declara mediante la extendspalabra clave. Una clase puede hacer referencia a sí misma usando la thispalabra clave y su superclase directa usando la superpalabra clave.

clase  Foo { }clase  Foobar extiende Foo {   }

Si una clase no especifica su superclase, implícitamente hereda de java.lang.Objectla clase. Por tanto, todas las clases en Java son subclases de Objectuna clase.

Si la superclase no tiene un constructor sin parámetros, la subclase debe especificar en sus constructores qué constructor de la superclase usar. Por ejemplo:

class  Foo { public Foo ( int n ) { // Hacer algo con n } }       clase  Foobar extiende Foo { número int privado ; // La superclase no tiene constructor sin parámetros // así que tenemos que especificar qué constructor de nuestra superclase usar y cómo         public Foobar ( int numero ) { super ( numero ); este . número = número ; } }        
Métodos primordiales

A diferencia de C++, todos finallos métodos que no son métodos en Java son virtuales y pueden ser anulados por las clases heredadas.

 operación de clase { public int doSomething () { return 0 ; } }        clase  NuevaOperación extiende Operación { @Override public int doSomething () { return 1 ; } }           
clases abstractas

Una clase abstracta es una clase que está incompleta o debe considerarse incompleta, por lo que no se puede crear una instancia.

Una clase C tiene métodos abstractos si se cumple alguna de las siguientes condiciones:

paquete org.dwwwp.test ; /** * @author jcrypto */ clase pública AbstractClass { cadena final estática privada hola ;         estático { Sistema . afuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución de bloque estático" ); hola = "hola desde " + AbstractClass . clase . obtenerNombre (); }           { Sistema . afuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución del bloque de instancia" ); }     public AbstractClass () { Sistema . afuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución del constructor" ); }       public static void hola () { Sistema . afuera . imprimirln ( hola ); } }      
paquete org.dwwwp.test ; /** * @author jcrypto */ clase pública CustomClass extiende AbstractClass {      estático { Sistema . afuera . println ( CustomClass . class . getName () + ": tiempo de ejecución de bloque estático" ); }      { Sistema . afuera . println ( CustomClass . class . getName () + ": tiempo de ejecución del bloque de instancia" ); }     public CustomClass () { Sistema . afuera . println ( CustomClass . class . getName () + ": tiempo de ejecución del constructor" ); }       public static void main ( String [] args ) { CustomClass nc = new CustomClass (); Hola (); //AbstractClass.hello();//también válido } }             

Producción:

org.dwwwp.test.AbstractClass: tiempo de ejecución de bloque estáticoorg.dwwwp.test.CustomClass: tiempo de ejecución de bloque estáticoorg.dwwwp.test.AbstractClass: tiempo de ejecución del bloque de instanciaorg.dwwwp.test.AbstractClass: tiempo de ejecución del constructororg.dwwwp.test.CustomClass: tiempo de ejecución del bloque de instanciaorg.dwwwp.test.CustomClass: tiempo de ejecución del constructorHola desde org.dwwwp.test.AbstractClass

Enumeraciones

Esta característica del lenguaje se introdujo en J2SE 5.0 . Técnicamente, las enumeraciones son un tipo de clase que contiene constantes de enumeración en su cuerpo. Cada constante de enumeración define una instancia del tipo de enumeración. No se pueden crear instancias de clases de enumeración en ningún lugar excepto en la propia clase de enumeración.

enum Temporada { INVIERNO , PRIMAVERA , VERANO , OTOÑO }      

Las constantes de enumeración pueden tener constructores, que se llaman cuando se carga la clase:

enumeración pública Temporada { INVIERNO ( "Frío" ), PRIMAVERA ( "Más cálido" ), VERANO ( "Caliente" ), OTOÑO ( "Más fresco" );        Temporada ( descripción de cadena ) { this . descripción = descripción ; }       descripción de cadena final privada ;    cadena pública getDescription () { devolver descripción ; } }      

Las enumeraciones pueden tener cuerpos de clase, en cuyo caso se tratan como clases anónimas que extienden la clase enum:

enumeración pública Temporada { INVIERNO { String getDescription () { return "frío" ;} }, PRIMAVERA { String getDescription ( ) { return "caliente" ;} }, VERANO { String getDescription () { return "caliente" ;} }, OTOÑO { String getDescription () { return "refrigerador" ;} }; }                               

Interfaces

Las interfaces son tipos que no contienen campos y normalmente definen una serie de métodos sin una implementación real. Son útiles para definir un contrato con cualquier número de implementaciones diferentes. Cada interfaz es implícitamente abstracta. A los métodos de interfaz se les permite tener un subconjunto de modificadores de acceso según la versión del idioma, strictfplo que tiene el mismo efecto que para las clases, y también staticdesde Java SE 8.

interfaz  ActionListener { int ACTION_ADD = 0 ; intACCIÓN_REMOVE = 1 ;acción nula seleccionada ( acción int ); }             

Implementando una interfaz

Una interfaz es implementada por una clase usando la implementspalabra clave. Se permite implementar más de una interfaz, en cuyo caso se escriben después de implementsla palabra clave en una lista separada por comas. La clase que implementa una interfaz debe anular todos sus métodos; de lo contrario, debe declararse abstracta.

interfaz  RequestListener { int requestReceived (); }   clase  ActionHandler implementa ActionListener , RequestListener { public void actionSelected ( int action ) { }           solicitud int públicarecibida () { } }    //Método de llamada definido por la interfaz RequestListener oyente = new ActionHandler (); /*ActionHandler se puede  representar como RequestListener...*/ oyente . Solicitud recibida (); /*...y por lo tanto se sabe que implementa  el método requestReceived()*/      

Interfaces funcionales y expresiones lambda.

Estas características se introdujeron con el lanzamiento de Java SE 8. Una interfaz se convierte automáticamente en una interfaz funcional si define solo un método. En este caso, una implementación se puede representar como una expresión lambda en lugar de implementarla en una nueva clase, lo que simplifica enormemente la escritura de código en el estilo funcional . Opcionalmente, las interfaces funcionales se pueden anotar con la @FunctionalInterfaceanotación, que le indicará al compilador que verifique si la interfaz realmente se ajusta a una definición de interfaz funcional.

// Una interfaz funcional @FunctionalInterface interfaz  Cálculo { int calcular ( int algúnNúmero , int algúnOtroNúmero ); }      // Un método que acepta esta interfaz como parámetro int runCalculation ( Cálculo de cálculo ) { cálculo de retorno . calcular ( 1 , 2 ); }      // Usando una lambda para llamar al método runCalculation (( número , otroNúmero ) -> número + otroNúmero );     // Código equivalente que utiliza una clase anónima en su lugar runCalculation ( new Calculation () { @Override public int calcular ( int algúnNumber , int someOtherNumber ) { return someNumber + someOtherNumber ; } })               

No es necesario especificar completamente los tipos de parámetros de Lambda y se pueden inferir de la interfaz que implementa. El cuerpo de Lambda se puede escribir sin un bloque de cuerpo ni una returndeclaración si es solo una expresión. Además, para aquellas interfaces que solo tienen un único parámetro en el método, se pueden omitir los corchetes. [8]

// Misma llamada que la anterior, pero con tipos completamente especificados y un bloque de cuerpo runCalculation (( int number , int otherNumber ) -> { return number + otherNumber ; });         // Una interfaz funcional con un método que tiene un solo parámetro interface  StringExtender { String extendString ( String input ); }    // Inicializando una variable de este tipo usando un StringExtender extensor lambda = entrada -> entrada + "Extendido" ;       

Referencias de métodos

No es necesario utilizar lambdas cuando ya existe un método con nombre compatible con la interfaz. Este método se puede pasar en lugar de una lambda utilizando una referencia de método. Hay varios tipos de referencias de métodos:

El código anterior cuyas llamadas runCalculationpodrían reemplazarse con lo siguiente usando las referencias del método:

ejecutarCalculación ( Entero :: suma );

Herencia

Las interfaces pueden heredar de otras interfaces al igual que las clases. A diferencia de las clases, se le permite heredar de múltiples interfaces. Sin embargo, es posible que varias interfaces tengan un campo con el mismo nombre, en cuyo caso se convierte en un único miembro ambiguo al que no se puede acceder.

/* La clase que implementa esta interfaz debe implementar métodos de ActionListener y RequestListener */ interface  EventListener extends ActionListener , RequestListener { }     

Métodos predeterminados

Java SE 8 introdujo métodos predeterminados para las interfaces, lo que permite a los desarrolladores agregar nuevos métodos a las interfaces existentes sin romper la compatibilidad con las clases que ya implementan la interfaz. A diferencia de los métodos de interfaz normales, los métodos predeterminados tienen un cuerpo que será llamado en el caso de que la clase de implementación no lo anule.

interfaz  StringManipulator { String extendString ( entrada de cadena ); // Un método que es opcional para implementar String predeterminado shortenString ( entrada de cadena ) { return input . subcadena ( 1 ); } }              // Esta es una clase válida a pesar de no implementar todos los métodos class  PartialStringManipulator implements StringManipulator { @Override public String extendString ( String input ) { return input + "Extendido" ; } }              

Métodos estáticos

Los métodos estáticos son otra característica del lenguaje introducida en Java SE 8. Se comportan exactamente de la misma manera que las clases.

interfaz  StringUtils { cadena estática shortenByOneSymbol ( entrada de cadena ) { entrada de retorno . subcadena ( 1 ); } }         StringUtils . shortenByOneSymbol ( "Prueba" );

métodos privados

Se agregaron métodos privados en la versión Java 9. Una interfaz puede tener un método con un cuerpo marcado como privado, en cuyo caso no será visible para las clases herederas. Se puede llamar desde métodos predeterminados con el fin de reutilizar el código.

 registrador de interfaz { valor predeterminado void logError () { log ( Nivel . ERROR ); }        valor predeterminado void logInfo () { log ( Nivel . INFO ); }      registro vacío privado ( Nivel nivel ) { SystemLogger . iniciar sesión ( nivel . id ); } }      

Anotaciones

Las anotaciones en Java son una forma de incrustar metadatos en el código. Esta característica del lenguaje se introdujo en J2SE 5.0 .

Tipos de anotaciones

Java tiene un conjunto de tipos de anotaciones predefinidos, pero se permite definir otros nuevos. Una declaración de tipo de anotación es un tipo especial de declaración de interfaz. Se declaran de la misma manera que las interfaces, excepto que la interfacepalabra clave va precedida por el @signo. Todas las anotaciones se extienden implícitamente desde java.lang.annotation.Annotationcualquier otra cosa y no pueden extenderse desde ella.

@interface Operaciones de bloqueo { }  

Las anotaciones pueden tener las mismas declaraciones en el cuerpo que las interfaces comunes, además se les permite incluir enumeraciones y anotaciones. La principal diferencia es que las declaraciones de métodos abstractos no deben tener ningún parámetro ni generar ninguna excepción. También pueden tener un valor predeterminado, que se declara utilizando la defaultpalabra clave después del nombre del método:

@interface BlockingOperations { boolean fileSystemOperations (); operaciones de red booleanas () predeterminado falso ; }        
Uso de anotaciones

Las anotaciones se pueden utilizar en cualquier tipo de declaración, ya sea paquete, clase (incluidas enumeraciones), interfaz (incluidas anotaciones), campo, método, parámetro, constructor o variable local. También se pueden utilizar con constantes de enumeración. Las anotaciones se declaran utilizando el @signo que precede al nombre del tipo de anotación, después del cual los pares elemento-valor se escriben entre paréntesis. A todos los elementos sin valor predeterminado se les debe asignar un valor.

@BlockingOperations ( /*mandatory*/ fileSystemOperations , /*opcional*/ networkOperations = true ) void openOutputStream () { //Método anotado }       

Además de la forma genérica, existen otras dos formas de declarar una anotación, que son taquigrafías. La anotación de marcador es una forma breve y se utiliza cuando no se asignan valores a los elementos:

@Unused // Taquigrafía de @Unused() void travelToJupiter () { }   

La otra forma abreviada se llama anotación de elemento único . Se utiliza con tipos de anotaciones que contienen solo un elemento o en el caso en que hay varios elementos presentes, pero solo uno de ellos carece de un valor predeterminado. En el formulario de anotación de un solo elemento, el nombre del elemento se omite y en su lugar solo se escribe el valor:

/* Equivalente a @BlockingOperations(fileSystemOperations = true). networkOperations tiene un valor predeterminado y no es necesario asignarle un valor */@BlockingOperations ( verdadero ) anula openOutputStream () { }  

Genéricos

Los genéricos , o tipos parametrizados, o polimorfismo paramétrico es una de las características principales introducidas en J2SE 5.0 . Antes de que se introdujeran los genéricos, era necesario declarar todos los tipos explícitamente. Con los genéricos se hizo posible trabajar de manera similar con diferentes tipos sin declarar los tipos exactos. El objetivo principal de los genéricos es garantizar la seguridad de tipos y detectar errores de tiempo de ejecución durante la compilación. A diferencia de C#, la información sobre los parámetros utilizados no está disponible en tiempo de ejecución debido al borrado de tipos . [9]

clases genéricas

Las clases se pueden parametrizar agregando una variable de tipo entre corchetes angulares ( <y >) después del nombre de la clase. Hace posible el uso de esta variable de tipo en miembros de clase en lugar de tipos reales. Puede haber más de un tipo de variable, en cuyo caso se declaran en una lista separada por comas.

Es posible limitar una variable de tipo a un subtipo de alguna clase específica o declarar una interfaz que debe ser implementada por el tipo. En este caso, a la variable de tipo se le añade la extendspalabra clave seguida del nombre de la clase o de la interfaz. Si la variable está restringida tanto por la clase como por la interfaz o si hay varias interfaces, el nombre de la clase se escribe primero, seguido de los nombres de las interfaces con & el signo utilizado como delimitador.

/* Esta clase tiene dos variables de tipo, T y V. T debe ser un subtipo de ArrayList e implementar la interfaz Formattable */ public class Mapper < T extends ArrayList & Formattable , V > { public void add ( T array , V item ) { // la matriz tiene el método add porque es una subclase de ArrayList . añadir artículo ) ; } }                  

Cuando se declara una variable de un tipo parametrizado o se crea una instancia, su tipo se escribe exactamente en el mismo formato que en el encabezado de la clase, excepto que el tipo real se escribe en el lugar de la declaración de la variable de tipo.

/* Mapper se crea con CustomList como T e Integer como V. CustomList debe ser una subclase de ArrayList e implementar Formattable */ Mapper < CustomList , Integer > mapper = new Mapper < CustomList , Integer > ();      

Desde Java SE 7, es posible utilizar un diamante ( <>) en lugar de argumentos de tipo, en cuyo caso se inferirá este último. El siguiente código en Java SE 7 es equivalente al código del ejemplo anterior:

Mapeador < ListaPersonalizada , Entero > mapeador = nuevo Mapeador <> ();     

Al declarar una variable para un tipo parametrizado, es posible utilizar comodines en lugar de nombres de tipo explícitos. Los comodines se expresan mediante ?signos de escritura en lugar del tipo real. Es posible limitar los tipos posibles a las subclases o superclases de alguna clase específica escribiendo la extendspalabra clave o la superpalabra clave correspondientemente seguida del nombre de la clase.

/* Cualquier instancia de Mapper con CustomList como primer parámetro puede usarse independientemente del segundo.*/ Mapper < CustomList , ?> mapper ; mapper = nuevo Mapper < Lista personalizada , booleano > (); mapper = nuevo Mapper < Lista personalizada , Entero > ();          /* No aceptará tipos que utilicen cualquier cosa que no sea una subclase de Número como segundo parámetro */ void addMapper ( Mapper < ?, ? extends Number > mapper ) { }      

Métodos genéricos y constructores.

El uso de genéricos puede limitarse a algunos métodos particulares; este concepto también se aplica a los constructores. Para declarar un método parametrizado, las variables de tipo se escriben antes del tipo de retorno del método en el mismo formato que para las clases genéricas. En el caso del constructor, las variables de tipo se declaran antes del nombre del constructor.

class  Mapper { // La clase en sí no es genérica, el constructor es < T , V > Mapper ( matriz T , elemento V ) { } }          /* Este método aceptará solo matrices del mismo tipo que el tipo de elemento buscado o su subtipo*/ static < T , V extends T > boolean contains ( T item , V [] arr ) { for ( T currentItem : arr ) { if ( artículo . es igual a ( artículo actual )) { return true ; } } falso retorno ; }                         

Interfaces genéricas

Las interfaces se pueden parametrizar de manera similar a las clases.

interfaz  Ampliable < T extiende Número > { void addItem ( T elemento ); }      // Esta clase está parametrizada class  Array < T extends Number > implements Expandable < T > { void addItem ( T item ) { } }          // Y esto no lo es y usa un tipo explícito en su lugar class  IntegerArray implements Expandable < Integer > { void addItem ( Integer item ) { } }        

Ver también

Referencias

  1. ^ "Operadores (Tutoriales de Java™ > Aprendizaje del lenguaje Java > Conceptos básicos del lenguaje)". docs.oracle.com . Oracle y/o sus filiales . Consultado el 16 de junio de 2015 .
  2. ^ "La declaración de cambio (Tutoriales de Java™ > Aprendizaje del lenguaje Java > Conceptos básicos del lenguaje)". docs.oracle.com . Consultado el 15 de agosto de 2021 .
  3. ^ Owens, Sean. "Java y unsigned int, unsigned short, unsigned byte, unsigned long, etc. (O más bien, la falta de ellos)".
  4. ^ "Tipos de datos primitivos".
  5. ^ JLS 8.4.3.3. Métodos finales
  6. ^ Redacción de clases y métodos finales
  7. ^ Teoría y práctica de Java: ¿es esa su respuesta final?
  8. ^ "Expresiones Lambda (Tutoriales de Java™ > Aprendizaje del lenguaje Java > Clases y objetos)". docs.oracle.com . Consultado el 8 de agosto de 2021 .
  9. ^ Genéricos en tiempo de ejecución (Guía de programación de C#)

enlaces externos