Este artículo incluye una lista de referencias generales , pero permanece en gran parte sin verificar porque carece de suficientes citas en línea correspondientes . ( Enero de 2014 ) ( Obtenga información sobre cómo y cuándo eliminar este mensaje de plantilla ) |
La sintaxis de Java se refiere al 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 en el transcurso de numerosas versiones importantes de JDK y ahora admite capacidades como programación genérica y literales de función (llamadas expresiones lambda en Java). Desde 2017, se lanza una nueva versión de JDK dos veces al año, y cada lanzamiento trae mejoras incrementales al lenguaje.
Conceptos básicos [ editar ]
Identificador [ editar ]
Un identificador es el nombre de un elemento en el código . Hay 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:
- Cualquier carácter Unicode que sea una letra (incluidas letras numéricas como números romanos ) o un dígito.
- Signo de moneda (como ¥).
- Conectando caracteres de puntuación (como _ ).
Un identificador no puede:
- Empiece con un dígito.
- Ser igual a una palabra clave reservada, literal nulo o literal booleano.
Palabras clave [ editar ]
abstracto | Seguir | por | nuevo | cambiar |
afirmar | defecto | ir | paquete | sincronizado |
booleano | hacer | si | privado | esta |
descanso | doble | implementos | protegido | lanzar |
byte | demás | importar | público | lanza |
caso | enumeración | en vez de | regreso | transitorio |
captura | se extiende | En t | corto | intentar |
carbonizarse | final | interfaz | estático | var |
clase | por fin | largo | estrictofp | vacío |
constante | flotador | nativo | súper | volátil |
tiempo |
Literales [ editar ]
Enteros | |
---|---|
binario (introducido en Java SE 7) | 0b11110101 ( 0b seguido de un número binario) |
octal | 0365 ( 0 seguido de un número octal) |
hexadecimal | 0xF5 ( 0x seguido de un número hexadecimal) |
decimal | 245 (número decimal) |
Valores de coma flotante | |
flotador | 23.5F , .5f , 1.72E3F (fracción decimal con un indicador de exponente opcional, seguida de F ) |
0x.5FP0F , 0x.5P-6f ( 0x seguido de una fracción hexadecimal con un indicador de exponente obligatorio y un sufijo F ) | |
doble | 23.5D , .5 , 1.72E3D (fracción decimal con un indicador de exponente opcional, seguido de D opcional ) |
0x.5FP0 , 0x.5P-6D ( 0x seguido de una fracción hexadecimal con un indicador de exponente obligatorio y un sufijo D opcional ) | |
Literales de carácter | |
carbonizarse | 'a' , 'Z' , '\ u0231' (carácter o un carácter de escape, entre comillas simples) |
Literales booleanos | |
booleano | verdadero , falso |
literal nulo | |
referencia nula | nulo |
Literales de cadena | |
Cuerda | "Hola, mundo" (secuencia de caracteres y caracteres de escape entre comillas dobles) |
Los personajes se escapan en cadenas | |
Carácter Unicode | \ u3876 ( \ u seguido del código unicode hexadecimal apunta hasta U + FFFF) |
octal de escape | \ 352 (número octal que no exceda de 377, precedido por una barra invertida) |
Linea de alimentación | \norte |
Retorno de carro | \ r |
Alimentación de formulario | \F |
Barra invertida | \\ |
Una frase | \ ' |
Cotización doble | \ " |
Pestaña | \ t |
Retroceso | \B |
Los literales enteros son de int
tipo por defecto a menos que el long
tipo se especifique agregando L
o l
sufijo 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 [ editar ]
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 instrucción asignando un valor.
int count ; // 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 varias variables del mismo tipo en una declaración utilizando una coma como delimitador.
int a , b ; // Declarando múltiples variables del mismo tipo int a = 2 , b = 3 ; // Declarar e inicializar múltiples variables del mismo tipo
Desde Java 10, es posible inferir tipos para las variables automáticamente usando 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 [ editar ]
Los separadores { y} significa 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 varios contextos.
Dentro de los cuerpos del método, se pueden usar llaves para crear nuevos ámbitos, como se indica a continuación:
void doSomething () { int una ; { int b ; a = 1 ; } a = 2 ; b = 3 ; // Ilegal porque la variable b está declarada en un ámbito interno .. }
Comentarios [ editar ]
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 */
, pueden extenderse a lo largo de 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 C.
// Este es un comentario de final de línea
Los comentarios de documentación en los archivos fuente son procesados por la herramienta Javadoc 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 se definen específicamente en la especificación del lenguaje.
/ ** * Este es un comentario de documentación. * * @ autor John Doe * /
Tipos universales [ editar ]
Las clases del paquete java.lang se importan implícitamente en cada programa, siempre que ningún tipo importado explícitamente tenga los mismos nombres. Los importantes incluyen:
- java.lang.Object
- 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 el autoboxing .
- java.lang.String
- 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 uno
int[]
que sea efectivamente UTF-32 . - java.lang.Throwable
- supertipo de todo lo que se puede lanzar o capturar con declaraciones
throw
y de Javacatch
.
Estructura del programa [ editar ]
Las aplicaciones Java constan de colecciones de clases. Las clases existen en paquetes, pero también se pueden anidar dentro de otras clases.
main
método [ editar ]
Cada aplicación Java debe tener un punto de entrada. Esto es cierto tanto para las aplicaciones de interfaz gráfica como para las aplicaciones de consola. El punto de entrada es el main
método. Puede haber más de una clase con un main
método, pero la clase principal siempre se define externamente (por ejemplo, en un archivo de manifiesto ). El método debe ser static
y se pasa 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
.
public static void main ( String [] args ) { }
Paquetes [ editar ]
Los paquetes son parte de un nombre de 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.InputStream
es un nombre de clase completamente calificado para la clase InputStream
que se encuentra en el paquete java.io
.
Un paquete se declara al comienzo del archivo con la package
declaración:
paquete myapplication.mylibrary ; clase pública MyClass { }
Las clases con el public
modificador deben colocarse en los archivos con el mismo nombre y extensión java y colocarse en carpetas anidadas correspondientes al nombre del paquete. La clase anterior tendrá la siguiente ruta: .myapplication.mylibrary.MyClass
myapplication/mylibrary/MyClass.java
Declaración de importación [ editar ]
Escriba la declaración de importación [ editar ]
Una declaración de importación de tipo 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 un solo tipo 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 myPackage ;import java.util.Random ; // Declaración de tipo únicopublic class ImportsTest { public static void main ( String [] args ) { / * La siguiente línea es equivalente a * java.util.Random random = new java.util.Random (); * Hubiera 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 de paquete. Una "importación estática" importa miembros del paquete.
importar java.util. * ; / * Esta forma de importar clases hace que todas las clases en el paquete java.util estén disponibles por nombre, podría usarse en lugar de la declaración de importación en el 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 [ editar ]
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:
import static java.lang.System.out ; // 'out' es un campo estático en java.lang.Systempublic class HelloWorld { 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. * / fuera . println ( "¡Hola mundo!" ); } }
Las declaraciones de importación bajo demanda permiten importar todos los campos del tipo:
importar static java.lang.System. * ; / * 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 en el ejemplo anterior. * /
Las constantes de enumeración también se pueden usar con la 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 usar declaraciones de importación estáticas en otra clase para recuperar las constantes de enumeración:
import screen.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 [ editar ]
Los operadores en Java son similares a los de C ++ . Sin embargo, no existe un delete
operador debido a los mecanismos de recolección de basura en Java, y no hay operaciones en los punteros ya que Java no los admite. Otra diferencia es que Java tiene un operador de desplazamiento a la derecha sin firmar ( >>>
), mientras que el signo del operador de desplazamiento a la derecha de C depende del tipo. Los operadores en Java no se pueden sobrecargar .
Precedencia | Operador | Descripción | Asociatividad |
---|---|---|---|
1 | () | Invocación de método | De izquierda a derecha |
[] | Acceso a la matriz | ||
. | Selección de miembros de la clase | ||
2 | ++ -- | Incremento y decremento de sufijo [1] | |
3 | ++ -- | Incremento y decremento de prefijo | De derecha a izquierda |
+ - | Unario más y menos | ||
! ~ | NOT lógico y NOT bit a bit | ||
(type) val | Tipo elenco | ||
new | Creación de una instancia o matriz de clase | ||
4 | * / % | Multiplicación, división y módulo (resto) | De izquierda a derecha |
5 | + - | Adición y sustracción | |
+ | Concatenación de cadenas | ||
6 | << >> >>> | Desplazamiento a la izquierda bit a bit , desplazamiento a la derecha firmado y desplazamiento a la derecha sin firmar | |
7 | < <= | Relacional "menor que" y "menor o igual que" | |
> >= | Relacional "mayor que" y "mayor o igual que" | ||
instanceof | Comparación de tipos | ||
8 | == != | Relacional "igual a" y "no igual a" | |
9 | & | AND bit a bit y lógico | |
10 | ^ | XOR bit a bit y lógico (exclusivo o) | |
11 | | | OR bit a bit y lógico (inclusive o) | |
12 | && | Y condicional lógico | |
13 | || | OR condicional lógico | |
14 | c ? t : f | Ternaria condicional (ver :? ) | De derecha a izquierda |
15 | = | Asignación simple | |
+= -= | Asignación por suma y diferencia | ||
*= /= %= | Asignación por producto, cociente y resto | ||
<<= >>= >>>= | Asignación por desplazamiento a la izquierda bit a bit, desplazamiento a la derecha con signo y desplazamiento a la derecha sin firmar | ||
&= ^= |= | Asignación por AND, XOR y OR bit a bit |
Estructuras de control [ editar ]
Declaraciones condicionales [ editar ]
if
declaración [ editar ]
si las declaraciones en Java son similares a las de C y usan la misma sintaxis:
si ( i == 3 ) hacer Algo ();
if
La declaración puede incluir un else
bloque opcional , en cuyo caso se convierte en una declaración if-then-else:
if ( i == 2 ) {hacer Algo (); } else { doSomethingElse (); }
Al igual que C, la construcción else-if no implica ninguna palabra clave especial, se forma como una secuencia de declaraciones if-then-else independientes:
if ( i == 3 ) {hacer Algo (); } más si ( i == 2 ) { hacerAlgoElse (); } else { hacerAlgoDiferente (); }
Además, tenga en cuenta que el operador ?: Se puede utilizar en lugar de una declaración if simple, por ejemplo
int a = 1 ; int b = 2 ; int minVal = ( a < b ) ? a : b ;
switch
declaración [ editar ]
Sentencias switch en Java pueden utilizar byte
, short
, char
, y int
(nota: no long
) tipos de datos primitivos o sus correspondientes tipos de envoltura. A partir de J2SE 5.0, es posible utilizar tipos de enumeración . A partir de Java SE 7, es posible utilizar Strings. No se pueden utilizar otros tipos de referencia en switch
declaraciones.
Los valores posibles se enumeran mediante case
etiquetas. Estas etiquetas en Java pueden contener solo constantes (incluidas las constantes de enumeración y las constantes de cadena). La ejecución comenzará después de la etiqueta correspondiente a la expresión dentro de los corchetes. default
Puede estar presente una etiqueta opcional para declarar que el código siguiente se ejecutará si ninguna de las etiquetas de caso corresponde a la expresión.
El código de cada etiqueta termina con la break
palabra clave. Es posible omitirlo haciendo 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 (); // Se activa si ch == 'A' se rompe ; case 'B' : case 'C' : doSomethingElse (); // Se activa si ch == 'B' o ch == 'C' se rompen ; predeterminado : doSomethingDifferent (); // Activado en cualquier otro caso break ; }
switch
expresiones [ editar ]
Desde Java 14 es posible utilizar expresiones de cambio, que utilizan la nueva sintaxis de flechas:
var result = switch ( ch ) { caso 'A' -> Resultado . GRANDE ; caso 'B' , 'C' -> Resultado . FINO ; predeterminado -> lanzar nueva ThisIsNoGoodException (); };
Alternativamente, existe la posibilidad de expresar lo mismo con la yield
declaración, aunque se recomienda preferir la sintaxis de flecha porque evita el problema de caídas accidentales.
var result = switch ( ch ) { case 'A' : rendimiento del resultado . GRANDE ; caso 'B' : caso 'C' : rendimiento de resultado . FINO ; predeterminado : lanza una nueva ThisIsNoGoodException (); };
Declaraciones de iteración [ editar ]
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 tales declaraciones.
while
bucle [ editar ]
En el while
ciclo, la prueba se realiza antes de cada iteración.
while ( i < 10 ) {hacer Algo (); }
do ... while
bucle [ editar ]
En el do ... while
ciclo, 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 ( i < 10 );
for
bucle [ editar ]
for
Los bucles en Java incluyen un inicializador, una condición y una contraexpresión. Es posible incluir varias expresiones del mismo tipo utilizando una coma como delimitador (excepto en la condición). Sin embargo, a diferencia de C, la coma es solo un delimitador y no un operador.
para ( int i = 0 ; i < 10 ; i ++ ) {hacer Algo (); } // Un ciclo más complejo usando dos variables para ( int i = 0 , j = 9 ; i < 10 ; i ++ , j - = 3 ) { doSomething (); }
Como C, las tres expresiones son opcionales. El siguiente ciclo es infinito:
para (;;) {hacer Algo (); }
for
Bucle mejorado [ editar ]
Los forbucles 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 dada. Cada elemento es devuelto y accesible en el contexto del bloque de código. Cuando se ejecuta el bloqueo, 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.
para ( int i : intArray ) { doSomething ( i ); }
Saltar declaraciones [ editar ]
Etiquetas [ editar ]
A las etiquetas se les asignan puntos en el código que utilizan las declaraciones break
y continue
. Tenga en cuenta que la goto
palabra clave Java no se puede utilizar para saltar a puntos específicos del código.
inicio: algún método ();
break
declaración [ editar ]
La break
declaración sale del bucle o switch
declaración más cercana . La ejecución continúa en la declaración después de la declaración terminada, si la hubiera.
for ( int i = 0 ; i < 10 ; i ++ ) { while ( true ) { break ; } // Romperá hasta este punto }
Es posible salir del bucle externo usando etiquetas:
exterior: for ( int i = 0 ; i < 10 ; i ++ ) { while ( verdadero ) { romper exterior ; } } // Romperá hasta este punto
continue
declaración [ editar ]
La continue
declaración interrumpe la iteración actual de la declaración de control actual y comienza la siguiente iteración. El siguiente while
bucle en el código a continuación lee caracteres llamando getChar()
, omitiendo las declaraciones en el cuerpo del bucle si los caracteres son espacios:
int ch ; while ( ch == getChar ()) { if ( ch == '' ) { continuar ; // Omite el resto del ciclo while } // El resto del ciclo while, no se alcanzará si ch == '' doSomething (); }
Las etiquetas se pueden especificar en continue
declaraciones y break
declaraciones:
externo: para ( String str : stringsArr ) { char [] strChars = str . toCharArray (); para ( carbón ch : strChars ) { Si ( CH == '' ) { / * Continúa el ciclo externo y la siguiente secuencia se recupera del stringsArr * / siguen exterior ; } DoSomething ( CH ); } }
return
declaración [ editar ]
La return
declaració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 return
palabra clave. Si el método devuelve algo menos void
, debe usar la return
declaración para devolver algún valor.
void doSomething ( boolean streamClosed ) { // Si streamClosed es verdadero, la ejecución se detiene if ( streamClosed ) { return ; } readFromStream (); }int calcularSuma ( int a , int b ) { int resultado = a + b ; devolver resultado ; }
return
instrucción finaliza la ejecución inmediatamente, excepto en un caso: si la instrucción se encuentra dentro de un try
bloque y se complementa con un finally
, el control se pasa al finally
bloque.
vacío doSomething ( booleano streamClosed ) { try { si ( streamClosed ) { retorno ; } readFromStream (); } finalmente { / * Se llamará en último lugar incluso si no se llamó a readFromStream () * / freeResources (); } }
Declaraciones de manejo de excepciones [ editar ]
try-catch-finally
declaraciones [ editar ]
Las excepciones se gestionan dentro de try
... catch
bloques.
try { // Declaraciones que pueden generar excepciones methodThrowingExceptions (); } catch ( Exception ex ) { // Excepción capturada y manejada aquí reportException ( ex ); } finalmente { // Las sentencias siempre se ejecutan después de los bloques try / catch freeResources (); }
Las instrucciones dentro del try
bloque se ejecutan y, si alguna de ellas genera una excepción, la ejecución del bloque se interrumpe y el catch
bloque maneja la excepción . Puede haber varios catch
bloques, en cuyo caso se ejecuta el primer bloque con una variable de excepción cuyo tipo coincide con el tipo de la excepción lanzada.
Java SE 7 también introdujo cláusulas de captura múltiple además de cláusulas de captura única. 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í.
try { methodThrowingExceptions (); } catch ( IOException | IllegalArgumentException ex ) { // Tanto IOException como IllegalArgumentException serán capturados y manejados aquí reportException ( ex ); }
Si ningún catch
bloque coincide con el tipo de la excepción lanzada, la ejecución del bloque externo (o método) que contiene la declaración try
... catch
se interrumpe y la excepción se pasa hacia arriba y fuera del bloque contenedor (o método). La excepción se propaga hacia arriba a través de la pila de llamadas hasta que se encuentra un catch
bloque coincidente dentro de uno de los métodos actualmente activos. Si la excepción se propaga hasta el main
método superior sin que se encuentre un catch
bloque coincidente , se escribe una descripción textual de la excepción en el flujo de salida estándar.
Las sentencias dentro del finally
bloque siempre se ejecutan después de los bloques try
y catch
, tanto si se lanzó una excepción como si no e incluso si return
se alcanzó una sentencia. Estos bloques son útiles para proporcionar código de limpieza que se garantiza que siempre se ejecutará.
Los bloques catch
y finally
son opcionales, pero al menos uno u otro debe estar presente después del try
bloque.
try
-con-declaraciones de recursos [ editar ]
try
Las sentencias -with-resources son un tipo especial de try-catch-finally
sentencias introducidas como una implementación del patrón dispose en Java SE 7. En una try
sentencia -with-resources, la try
palabra clave es seguida por la inicialización de uno o más recursos que se liberan automáticamente cuando se try
ejecuta el bloque. Está terminado. Los recursos deben implementar java.lang.AutoCloseable
. try
No se requiere que las sentencias -with-resources tengan un catch
o un finally
bloque a diferencia de las try-catch-finally
sentencias normales .
try ( FileOutputStream fos = new FileOutputStream ( "nombre de archivo" ); XMLEncoder xEnc = nuevo XMLEncoder ( fos )) { xEnc . writeObject ( objeto ); } catch ( IOException ex ) { Logger . getLogger ( Serializador . clase . getName ()). log ( Nivel . SEVERE , nulo , ex ); }
Desde Java 9 es posible utilizar variables ya declaradas:
FileOutputStream fos = new FileOutputStream ( "nombre de archivo" ); XMLEncoder xEnc = nuevo XMLEncoder ( fos ); intente ( fos ; xEnc ) { xEnc . writeObject ( objeto ); } catch ( IOException ex ) { Logger . getLogger ( Serializador . clase . getName ()). log ( Nivel .SEVERO , nulo , ex ); }
throw
declaración [ editar ]
La throw
declaración se usa 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 throw
instrucción.
void methodThrowingExceptions ( Object obj ) { if ( obj == null ) { // Lanza una excepción del tipo NullPointerException throw new NullPointerException (); } // No se llamará, si el objeto es nulo doSomethingWithObject ( obj ); }
Control de concurrencia de subprocesos [ editar ]
Java tiene herramientas integradas para la programación de subprocesos múltiples . A los efectos de la sincronización de subprocesos, la synchronized
declaración se incluye en lenguaje Java.
Para sincronizar un bloque de código, está precedido por la synchronized
palabra clave seguida por el objeto de bloqueo dentro de los corchetes. Cuando el hilo en ejecución alcanza el bloque sincronizado, adquiere un bloqueo de exclusión mutua , ejecuta el bloque y luego lo libera. Ningún hilo puede entrar en este bloque hasta que se libere el bloqueo. Se puede utilizar como bloqueo cualquier tipo de referencia no nulo.
/ * Adquiere bloqueo en someObject. Debe ser de un tipo de referencia y no debe ser nulo * / sincronizado ( someObject ) { // Declaraciones sincronizadas }
assert
declaración [ editar ]
assert
Las declaraciones han estado disponibles desde J2SE 1.4 . Estos tipos de declaraciones se utilizan para hacer 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, assert
se usa la palabra clave seguida de una expresión condicional. Si evalúa false
cuando se ejecuta la instrucción, se lanza una excepción. Esta declaración puede incluir dos puntos seguidos de otra expresión, que actuará como mensaje de detalle de la excepción.
// Si n es igual a 0, se lanza AssertionError assert n ! = 0 ; / * Si n es igual a 0, AssertionError se lanzará con el mensaje después de los dos puntos * / assert n ! = 0 : "n era igual a cero" ;
Tipos primitivos [ editar ]
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 char
type, que se utiliza para representar unidades de código UTF-16. La falta de tipos sin firmar se compensa con la introducción de la operación de desplazamiento a la derecha sin firmar ( >>>
), que no está presente en C ++. No obstante, se han recibido críticas sobre la falta de compatibilidad con C y C ++ que esto provoca. [2]
Tipos primitivos | |||||
---|---|---|---|---|---|
Escribe un nombre | Clase de envoltura | Valor | Distancia | Tamaño | Valor por defecto |
byte | java.lang.Byte | entero | −128 hasta +127 | 8 bits (1 byte) | 0 |
short | java.lang.Short | entero | −32,768 hasta +32,767 | 16 bits (2 bytes) | 0 |
int | java.lang.Integer | entero | −2,147,483,648 a +2,147,483,647 | 32 bits (4 bytes) | 0 |
long | java.lang.Long | entero | −9,223,372,036,854,775,808 hasta +9,223,372,036,854,775,807 | 64 bits (8 bytes) | 0 |
float | java.lang.Float | número de coma flotante | ± 1,401298E − 45 hasta ± 3,402823E + 38 | 32 bits (4 bytes) | 0.0f [3] |
double | java.lang.Double | número de coma flotante | ± 4.94065645841246E − 324 hasta ± 1.79769313486232E + 308 | 64 bits (8 bytes) | 0.0 |
boolean | java.lang.Boolean | Booleano | true o false | 1 bit (1 bit) | false |
char | java.lang.Character | Unidad de código UTF-16 ( carácter BMP o parte de un par sustituto) | '\u0000' mediante '\uFFFF' | 16 bits (2 bytes) | '\u0000' |
char
no corresponde necesariamente 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 char
valores.
Boxeo y unboxing [ editar ]
Esta función de idioma se introdujo en J2SE 5.0 . El boxing 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:
int foo = 42 ; // Tipo primitivo Integer bar = foo ; / * foo está encajado en bar, bar es de tipo Integer, que sirve como envoltorio para int * / int foo2 = bar ; // Desempaquetado de nuevo al tipo primitivo
Tipos de referencia [ editar ]
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. El recolector de basura luego lo recolecta y lo destruye algún tiempo después.
Una variable de referencia es null
cuando no hace referencia a ningún objeto.
Matrices [ editar ]
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 [ editar ]
// Sintaxis larga int [] números = new int [] { 20 , 1 , 42 , 15 , 34 }; // Sintaxis corta int [] numbers2 = { 20 , 1 , 42 , 15 , 34 };
Matrices multidimensionales [ editar ]
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 están obligadas a ser rectangulares a diferencia de C:
int [] [] números = nuevo int [ 2 ] [] ; // Inicialización de la primera dimensión solamentenúmeros [ 0 ] = nuevo int [ 3 ] ; números [ 1 ] = nuevo int [ 2 ] ;
Clases [ editar ]
Las clases son los fundamentos de un lenguaje orientado a objetos como Java. Contienen miembros que almacenan y manipulan datos. Las clases se dividen en 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 [ editar ]
Clase de primer nivel | class Foo { // miembros de la clase } |
---|---|
Clase interior | class Foo { // Clase de nivel superior Clase Bar { // Clase interna } } |
Clase anidada | class Foo { // Clase de nivel superior static class Bar { // Clase anidada } } |
Clase local | class Foo { void bar () { class Foobar { // Clase local dentro de un método } } } |
Clase anónima | class Foo { void bar () { new Object () { // Creación de una nueva clase anónima ampliando Object }; } } |
Instanciación [ editar ]
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 new
operador y llamando al constructor de la clase.
Foo foo = nuevo Foo ();
Accediendo a miembros [ editar ]
Se accede a los miembros de las instancias y clases estáticas con el .
operador (punto).
Acceso a un miembro de la
instancia Se puede acceder a los miembros de la instancia a través del nombre de una variable.
String foo = "Hola" ; Barra de cadena = foo . toUpperCase ();
Acceso a un miembro de clase
estática Se accede a los miembros estáticos mediante 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 mediante el static
modificador.
public class Foo { public static void doSomething () { } }// Llamando al método estático Foo . hacer algo ();
Modificadores [ editar ]
Los modificadores son palabras clave que se utilizan para modificar declaraciones de tipos y miembros de tipos. En particular, hay un subgrupo que contiene los modificadores de acceso.
abstract
- Especifica que una clase solo sirve como clase base y no se puede crear una instancia.static
- Usado solo para clases miembro, especifica que la clase miembro no pertenece a una instancia específica de la clase contenedora.final
- Las clases marcadas comofinal
no pueden extenderse y no pueden tener subclases.strictfp
- Especifica que todas las operaciones de punto flotante deben realizarse de acuerdo con IEEE 754 y prohíbe el uso de precisión mejorada para almacenar resultados intermedios.
Modificadores de acceso [ editar ]
Los modificadores de acceso , o modificadores de herencia , establecen la accesibilidad de clases, métodos y otros miembros. Los miembros marcados como public
pueden ser contactados desde cualquier lugar. Si una clase o su miembro no tiene modificadores, se asume el acceso predeterminado.
public class Foo { int go () { return 0 ; } Bar de clases privadas { } }
La siguiente tabla muestra si el código dentro de una clase tiene acceso a la clase o al método dependiendo de la ubicación de la clase de acceso y el modificador para la clase o miembro de clase accedido:
Modificador | Misma clase o clase anidada | Otra clase dentro del mismo paquete | Clase extendida dentro de otro paquete | No extendido dentro de otro paquete |
---|---|---|---|---|
private | sí | no | no | no |
predeterminado (paquete privado) | sí | sí | no | no |
protected | sí | sí | sí | no |
public | sí | sí | sí | sí |
Constructores e inicializadores [ editar ]
Un constructor es un método especial que se llama cuando se inicializa un objeto. Su propósito es inicializar los miembros del objeto. Las principales diferencias entre los constructores y los métodos ordinarios son que los constructores se llaman solo 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:
class Foo { String str ; Foo () { // Constructor sin argumentos // Inicialización } Foo ( String str ) { // Constructor con un argumento this . str = str ; } }
Los inicializadores son bloques de código que se ejecutan cuando se crea una clase o 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 static
palabra clave:
class Foo { static { // Inicialización } }
Una clase se crea solo 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 la llamada 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, por lo 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 se puede anular para implementar la finalización.
Métodos [ editar ]
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, por lo general, algunos parámetros se inicializan 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 ++, los métodos en Java no pueden tener valores de argumento predeterminados y los métodos suelen estar sobrecargados.
class 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 en un objeto, o en el caso de un método estático, también en el nombre de una clase.
Foo foo = nuevo Foo (); int resultado = foo . barra ( 7 , 2 ); // Se llama al método no estático en fooint finalResult = Math . abs ( resultado ); // Llamada al método estático
La throws
palabra clave indica que un método lanza 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 [ editar ]
abstract
- Los métodos abstractos solo pueden estar presentes en clases abstractas , tales métodos no tienen cuerpo y deben anularse en una subclase a menos que sea abstracto en sí mismo.static
- Hace que el método sea estático y accesible sin la creación de una instancia de clase. Sin embargo, los métodos estáticos no pueden acceder a miembros no estáticos de la misma clase.final
- Declara que el método no se puede invalidar en una subclase.native
- Indica que este método se implementa a través de JNI en código dependiente de la plataforma. La implementación real ocurre fuera del código Java, y tales métodos no tienen cuerpo.strictfp
- Declara conformidad estricta con IEEE 754 en la realización de operaciones de punto flotante.synchronized
- Declara que un hilo que ejecuta este método debe adquirir monitor. Para lossynchronized
métodos, el monitor es la instancia de la clase ojava.lang.Class
si el método es estático.- Modificadores de acceso: idénticos a los que se utilizan con las clases.
Varargs [ editar ]
Esta función de idioma 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 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.
vacío PrintReport ( Cadena de cabecera , int ... números ) { // número representa varargs sistema . fuera . println ( encabezado ); para ( int num : números ) { System . fuera . println ( num ); } }// Llamando al método varargs printReport ( "Datos de informe" , 74 , 83 , 25 , 96 );
Campos [ editar ]
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 { barra doble = 2.3 ; }
Modificadores [ editar ]
static
- Hace que el campo sea un miembro estático.final
- Permite que el campo se inicialice solo una vez en un constructor o dentro del bloque de inicialización o durante su declaración, lo que ocurra primero.transient
- Indica que este campo no se almacenará durante la serialización .volatile
- Si se declara un campovolatile
, se garantiza que todos los subprocesos vean un valor coherente para la variable.
Herencia [ editar ]
Las clases en Java solo pueden heredar de una clase. Una clase puede derivarse de cualquier clase que no esté marcada como final
. La herencia se declara mediante la extends
palabra clave. Una clase puede hacer referencia a sí misma usando la this
palabra clave y su superclase directa usando la super
palabra clave.
class Foo {}clase Foobar extiende Foo {}
Si una clase no especifica su superclase, hereda implícitamente de la java.lang.Object
clase. Por tanto, todas las clases en Java son subclases de Object
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 ) { // Haz algo con n } }la 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 número ) { super ( número ); esto . número = número ; } }
Métodos anuladores [ editar ]
A diferencia de C ++, todos los final
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 ; } }la clase NewOperation extiende la operación { @Override public int doSomething () { return 1 ; } }
Clases abstractas [ editar ]
Una clase abstracta es una clase que está incompleta o que se considera incompleta. Las clases normales pueden tener métodos abstractos, es decir, métodos que están declarados pero aún no implementados, solo si son clases abstractas. Una clase C tiene métodos abstractos si se cumple alguna de las siguientes condiciones:
- C contiene explícitamente una declaración de un método abstracto.
- Cualquiera de las superclases de C tiene un método abstracto y C no declara ni hereda un método que lo implemente.
- Una superinterfaz directa de C declara o hereda un método (que por lo tanto es necesariamente abstracto) y C ni declara ni hereda un método que lo implemente.
- Se puede instanciar una subclase de una clase abstracta que no es abstracta en sí misma, lo que da como resultado la ejecución de un constructor para la clase abstracta y, por lo tanto, la ejecución de los inicializadores de campo para las variables de ejemplo de esa clase.
paquete org.dwwwp.test ;/ ** * @author jcrypto * / public class AbstractClass { saludo de cadena final estático privado ; static { System . fuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución del bloque estático" ); hola = "hola de" + AbstractClass . clase . getName (); } { System . fuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución del bloque de instancia" ); } public AbstractClass () { System . fuera . println ( AbstractClass . class . getName () + ": tiempo de ejecución del constructor" ); } public static void hola () { System . fuera . println ( hola ); } }
paquete org.dwwwp.test ;/ ** * @author jcrypto * / public class CustomClass extiende AbstractClass { static { System . fuera . println ( CustomClass . class . getName () + ": tiempo de ejecución del bloque estático" ); } { System . fuera . println ( CustomClass . class . getName () + ": tiempo de ejecución del bloque de instancia" ); } public CustomClass () { System . fuera . 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 instanciasorg.dwwwp.test.CustomClass: tiempo de ejecución del constructorhola desde org.dwwwp.test.AbstractClass
Enumeraciones [ editar ]
Esta función de idioma se introdujo en J2SE 5.0 . Técnicamente, las enumeraciones son un tipo de clase que contiene constantes enum en su cuerpo. Cada constante de enumeración define una instancia del tipo de enumeración. Las clases de enumeración no se pueden instanciar en ningún lugar excepto en la propia clase de enumeración.
enum Temporada { INVIERNO , PRIMAVERA , VERANO , OTOÑO }
Se permite que las constantes de enumeración tengan constructores, que se llaman cuando se carga la clase:
enumeración pública Temporada { INVIERNO ( "Frío" ), PRIMAVERA ( "Más cálido" ), VERANO ( "Calor" ), OTOÑO ( "Más frío" ); Temporada ( descripción de la cadena ) { esto . descripción = descripción ; } descripción de cadena final privada ; public String getDescription () { descripción de retorno ; } }
Las enumeraciones pueden tener cuerpos de clase, en cuyo caso se tratan como clases anónimas extendiendo la clase enum:
public enum Season { INVIERNO { String getDescription () { return "cold" ;} }, PRIMAVERA { String getDescription () { return "warmer" ;} }, VERANO { String getDescription () { return "hot" ;} }, OTOÑO { String getDescription () { return "más fresco" ;} }; }
Interfaces [ editar ]
Las interfaces son tipos que no contienen campos y generalmente definen varios 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. Los métodos de interfaz pueden tener un subconjunto de modificadores de acceso según la versión del idioma strictfp
, lo que tiene el mismo efecto que para las clases, y también static
desde Java SE 8.
interfaz ActionListener { int ACTION_ADD = 0 ; int ACTION_REMOVE = 1 ; void actionSelected ( int acción ); }
Implementando una interfaz [ editar ]
Una interfaz es implementada por una clase usando la implements
palabra clave. Se permite implementar más de una interfaz, en cuyo caso se escriben después de la implements
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 como abstracta.
interfaz RequestListener { int requestReceived (); }class ActionHandler implementa ActionListener , RequestListener { public void actionSelected ( int action ) { } public int requestReceived () { } }// Método de llamada definido por la interfaz RequestListener listener = new ActionHandler (); / * ActionHandler se puede representar como RequestListener ... * / listener . requestReceived (); /*... y por lo tanto se sabe que implementa el método requestReceived () * /
Interfaces funcionales y expresiones lambda [ editar ]
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 . Las interfaces funcionales se pueden anotar opcionalmente con la @FunctionalInterface
anotació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 interface Calculation { int calcular ( int someNumber , int someOtherNumber ); }// 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 (( number , otherNumber ) -> number + otherNumber );// Código equivalente que usa una clase anónima en su lugar runCalculation ( new Calculation () { @Override public int calculate ( int someNumber , int someOtherNumber ) { return someNumber + someOtherNumber ; } })
Los tipos de parámetros de Lambda no tienen que estar completamente especificados y se pueden inferir de la interfaz que implementa. El cuerpo de Lambda se puede escribir sin un bloque de cuerpo y una return
declaració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.
// Misma llamada que la anterior, pero con tipos completamente especificados y un bloque de cuerpo runCalculation (( int número , int otherNumber ) -> { return number + otherNumber ; });// Una interfaz funcional con un método que tiene solo una interfaz de un solo parámetro StringExtender { String extendString ( String input ); }// Inicializando una variable de este tipo usando un lambda StringExtender extender = input -> input + "Extended" ;
Referencias de métodos [ editar ]
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 un lambda utilizando una referencia de método. Hay varios tipos de referencias a métodos:
Tipo de referencia | Ejemplo | Lambda equivalente |
---|---|---|
Estático | Integer::sum | (number, otherNumber) -> number + otherNumber |
Unido | "LongString"::substring | index -> "LongString".substring(index) |
Sin consolidar | String::isEmpty | string -> string.isEmpty() |
Constructor de clases | ArrayList<String>::new | capacity -> new ArrayList<String>(capacity) |
Constructor de matrices | String[]::new | size -> new String[size] |
El código arriba del cual las llamadas runCalculation
podrían reemplazarse con lo siguiente usando las referencias del método:
runCalculation ( Integer :: sum );
Herencia [ editar ]
Las interfaces pueden heredar de otras interfaces al igual que las clases. A diferencia de las clases, se 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 extiende ActionListener , RequestListener { }
Métodos predeterminados [ editar ]
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 se llamará en el caso si la clase de implementación no lo anula.
interfaz StringManipulator { String extendString ( entrada de cadena ); // Un método que es opcional para implementar String shortenString predeterminado ( String input ) { return input . subcadena ( 1 ); } } // Esta es una clase válida a pesar de no implementar todos los métodos. Clase PartialStringManipulator implementa StringManipulator { @Override public String extendString ( String input ) { return input + "Extended" ; } }
Métodos estáticos [ editar ]
Los métodos estáticos son otra característica del lenguaje introducida en Java SE 8. Se comportan exactamente de la misma manera que en las clases.
interfaz StringUtils { cadena estática shortenByOneSymbol ( cadena de entrada ) { entrada de retorno . subcadena ( 1 ); } } StringUtils . shortenByOneSymbol ( "Prueba" );
Métodos privados [ editar ]
Los métodos privados se agregaron en la versión de Java 9. Una interfaz puede tener un método con un cuerpo marcado como privado, en cuyo caso no será visible para las clases heredadas. Se puede llamar desde métodos predeterminados con el propósito de reutilizar el código.
interfaz Logger { default void logError () { log ( Level . ERROR ); } por defecto void logInfo () { log ( Nivel . INFO ); } registro de anulación privado ( nivel de nivel ) { SystemLogger . log ( nivel . id ); } }
Anotaciones [ editar ]
Las anotaciones en Java son una forma de incrustar metadatos en el código. Esta función de idioma se introdujo en J2SE 5.0 .
Tipos de anotaciones [ editar ]
Java tiene un conjunto de tipos de anotaciones predefinidos, pero se le 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 forma que las interfaces, excepto que la interface
palabra clave está precedida por el @
signo. Todas las anotaciones se amplían implícitamente java.lang.annotation.Annotation
y no se pueden ampliar desde ninguna otra cosa.
@interface BlockingOperations { }
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 parámetros ni generar excepciones. También pueden tener un valor predeterminado, que se declara usando la default
palabra clave después del nombre del método:
@interface BlockingOperations { fileSystemOperations booleano (); boolean networkOperations () predeterminado false ; }
Uso de anotaciones [ editar ]
Las anotaciones se pueden usar en cualquier tipo de declaración, ya sea paquete, clase (incluidas las enumeraciones), interfaz (incluidas las anotaciones), campo, método, parámetro, constructor o variable local. También se pueden usar con constantes enum. 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 corchetes. A todos los elementos sin valor predeterminado se les debe asignar un valor.
@BlockingOperations ( / * obligatorio * / 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 abreviaturas. La anotación de marcador es una forma corta, se usa cuando no se asignan valores a los elementos:
@Unused // Abreviatura de @Unused () void travelToJupiter () { }
La otra forma corta se llama anotación de elemento único . Se utiliza con tipos de anotaciones que contienen solo un elemento o en el caso de que haya varios elementos, pero solo uno de ellos carece de un valor predeterminado. En la forma 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 asignar un valor * /@BlockingOperations ( verdadero ) void openOutputStream () { }
Genéricos [ editar ]
Genéricos , o tipos parametrizados, o polimorfismo paramétrico es una de las principales características introducidas en J2SE 5.0 . Antes de que se introdujeran los genéricos, se requería declarar todos los tipos explícitamente. Con los genéricos fue 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 los 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 tipo . [4]
Clases genéricas [ editar ]
Las clases se pueden parametrizar agregando una variable de tipo entre paréntesis 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 una variable de tipo, 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, la variable de tipo se agrega con la extends
palabra clave seguida del nombre de la clase o 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 una interfaz formateable * / public class Mapper < T extiende ArrayList & Formattable , V > { public void add ( T array , V item ) { // la matriz tiene el método add porque es una matriz de subclase ArrayList . agregar ( elemento ); } }
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 lugar de la declaración de variable de tipo.
/ * Mapper se crea con CustomList como T y 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 usar 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:
Mapper < CustomList , Integer > mapper = new Mapper <> ();
Al declarar una variable para un tipo parametrizado, es posible utilizar comodines en lugar de nombres de tipos explícitos. Los comodines se expresan escribiendo un ?
signo en lugar del tipo real. Es posible limitar los tipos posibles a las subclases o superclases de alguna clase específica escribiendo la extends
palabra clave o la super
palabra clave seguida correspondientemente por el nombre de la clase.
/ * Cualquier Mapper ejemplo con CustomList como el primer parámetro se puede utilizar independientemente de la segunda uno * /. Mapper < CustomList , ?> Mapper ; mapper = new Mapper < CustomList , Boolean > (); mapper = new Mapper < CustomList , Integer > ();/ * No aceptará tipos que usen nada más que una subclase de Number como segundo parámetro * / void addMapper ( Mapper <? , ? Extiende Number > mapper ) { }
Métodos y constructores genéricos [ editar ]
El uso de genéricos puede estar limitado 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 extiende T > booleano contiene ( T elemento , V [] arr ) { para ( T currentItem : arr ) { if ( item . es igual a ( currentItem )) { devuelve verdadero ; } } devuelve falso ; }
Interfaces genéricas [ editar ]
Las interfaces se pueden parametrizar de manera similar a las clases.
interfaz Expandible < T extiende Número > { void addItem ( elemento T ); }// Esta clase está parametrizada class Array < T amplía Número > implementa Expandable < T > { void addItem ( T item ) { } }// Y esto no es y usa un tipo explícito en su lugar class IntegerArray implementa Expandable < Integer > { void addItem ( Integer item ) { } }
Ver también [ editar ]
- Plataforma Java, edición estándar
Referencias [ editar ]
- ^ "Operadores (Tutoriales de Java ™> Aprendizaje del lenguaje Java> Conceptos básicos del lenguaje)" . docs.oracle.com . Oracle y / o sus afiliados . Consultado el 16 de junio de 2015 .
- ^ Owens, Sean. "Java y unsigned int, unsigned short, unsigned byte, unsigned long, etc. (O más bien, la falta de ellos)" .
- ^ "Tipos de datos primitivos" .
- ^ Genéricos en el tiempo de ejecución (Guía de programación de C #)
- Patrick Naughton , Herbert Schildt . Java 2: The Complete Reference , tercera edición. The McGraw-Hill Companies, 1999. ISBN 0-07-211976-4
- Vermeulen; Caballo amblador; Bumgardner; Metz; Misfeldt; Shur; Thompson (2000). Los elementos del estilo Java . Prensa de la Universidad de Cambridge. ISBN 0-521-77768-2.
- Gosling, James ; Joy, Bill ; Steele, Guy ; Bracha, Gillad (2005). Especificación del lenguaje Java (3ª ed.). Addison-Wesley Professional . Consultado el 3 de diciembre de 2008 .
Enlaces externos [ editar ]
Wikilibros tiene un libro sobre el tema: Programación Java / Sintaxis |
- Especificación del lenguaje Java, tercera edición Descripción autorizada del lenguaje Java
- Javadocs de la API de Java SE 10