





























Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Prepara tus exámenes
Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity
Prepara tus exámenes con los documentos que comparten otros estudiantes como tú en Docsity
Encuentra los documentos específicos para los exámenes de tu universidad
Estudia con lecciones y exámenes resueltos basados en los programas académicos de las mejores universidades
Responde a preguntas de exámenes reales y pon a prueba tu preparación
Consigue puntos base para descargar
Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium
Comunidad
Pide ayuda a la comunidad y resuelve tus dudas de estudio
Ebooks gratuitos
Descarga nuestras guías gratuitas sobre técnicas de estudio, métodos para controlar la ansiedad y consejos para la tesis preparadas por los tutores de Docsity
Asignatura: Elements de programacio, Profesor: , Carrera: Enginyeria Informàtica, Universidad: UB
Tipo: Apuntes
1 / 37
Esta página no es visible en la vista previa
¡No te pierdas las partes importantes!






























Java es un lenguaje con control fuerte de Tipos ( Strongly Typed ). Esto significa que cada variable y cada expresión tiene un Tipo que es conocido en el momento de la compilación. El Tipo limita los valores que una variable puede contener, limita las operaciones soportadas sobre esos valores y determina el significado de la operaciones. El control fuerte de tipos ayuda a detectar errores en tiempo de compilación.
En Java existen dos categorias de Tipos:
Las referencias se usan para manipular objetos. Se verán en una lección posterior.
Los tipos primitivos son los que permiten manmipular valores numéricos (con distintos grados de precisión), caracteres y valores booleanos (verdadero / falso). Los Tipos Primitivos son:
El tamaño de los tipos de datos no depende de la implementación de Java. Son siempre los mismos.
Una variable es un área en memoria que tiene un nombre y un Tipo asociado. El Tipo es o bien un Tipo primitivo o una Referencia.
Es obligatorio declarar las variables antes de usarlas. Para declararlas se indica su nombre y su Tipo, de la siguiente forma:
tipo_variable nombre ;
Ejemplos:
int i ; // Declaracion de un entero char letra ; // Declaracion de un caracter boolean flag ; // Declaracion de un booleano
Se pueden asignar valores a las variables mediante la instrucción de asignación. Por ejemplo:
i = 5; // a la variable i se le asigna el valor 5 letra = 'c'; // a la variable letra se le asigna el valor 'c'
flag = false ; // a la variable flag se le asigna el valor false
La declaración y la combinación se pueden combinar en una sola expresión: int i = 5 ; char letra = 'c' ; boolean flag = false;
En los literales numéricos puede forzarse un tipo determinado con un sufijo:
En los literales numéricos para float y double puede usarse el exponente (10 elevado a...) de la forma: 1.5e3D (equivale a 1500) Literales hexadecimales: Al valor en hexadecimal se antepone el símbolo 0x. Por ejemplo: 0xf (valor 15) Literales booleanos: true (verdadero) y false (falso)
Literales caracter: Un caracter entre apóstrofes (') o bien una sequencia de escape (también entre '). Las secuencias de escape están formadas por el símbolo \ y una letra o un número. Algunas secuencias de escape útiles:
La siguiente tabla muestra un resumen de los operadores existentes para las distrintas clases de tipos primitivos. El grupo 'Enteros' incluye byte, short, int, long y char. El grupo 'Coma flotante' incluye float and double.
Tipos Grupo de operadores Operadores
Enteros Operadores de comparación que devuelven un valor boolean
< (menor) , <= (menor o igual) , > (mayor), >= (mayor o igual), == (igual), != (distinto) Operadores numéricos, que devuelven un valor int o long
Coma flotante
Operadores de comparación que devuelven un valor boolean
< (menor) , <= (menor o igual) , > (mayor), >= (mayor o igual), ==
Por ejemplo:
int x; x = sumaEnteros(2,3);
Nota: Esta sintaxis no está completa, pero sirve para nuestros propósitos en este momento. La sintaxis completa se verá cuando se hable de objetos.
Aunque el método no reciba ningún argumento, los paréntesis en la llamada son obligatorios. Por ejemplo para llamar a la función haceAlgo, simplemente se pondría:
haceAlgo();
Observese que como la función tampoco devuelve ningún valor no se asigna a ninguna variable. (No hay nada que asignar).
Las clases son el mecanismo por el que se pueden crear nuevos Tipos en Java. Las clases son el punto central sobre el que giran la mayoría de los conceptos de la Orientación a Objetos.
Una clase es una agrupación de datos y de código que actua sobre esos datos, a la que se le da un nombre.
Una clase contiene:
La sintaxis general para la declaración de una clase es:
modificadores class nombre_clase { declaraciones_de_miembros ; }
Por ejemplo:
class Punto { int x; int y; }
Los modificadores son palabras clave que afectan al comportamiento de la clase. Los iremos viendo progresivamente en los sucesivos capítulos.
Un objeto es una instancia (ejemplar) de una clase. La clase es la definición general y el objeto es la materialización concreta (en la memoria del ordenador) de una clase.
El fenómeno de crear objetos de una clase se llama instanciación.
Los objetos se manipulan con referencias. Una referencia es una variable que apunta a un objeto. Las referencias se declaran igual que las variables de Tipos primitivos (tipo nombre). Los objetos se crean (se instancian) con el operador de instanciación new.
Ejemplo:
Punto p; p = new Punto();
La primera línea del ejemplo declara una referencia (p) que es de Tipo Punto. La referencia no apunta a ningún sitio. En la segunda línea se crea un objeto de Tipo Punto y se hace que la referencia p apunte a él. Se puede hacer ambas operaciones en la misma expresión:
Punto p = new Punto();
A los miembros de un objeto se accede a través de su referencia. La sintaxis es:
nombre_referencia. miembro
En el ejemplo, se puede poner:
p.x = 1; p.y = 3;
Se puede visualizar gráficamente los datos primitivos, referencias y objetos de la siguiente forma:
Es importante señalar que en el ejemplo, p no es el objeto. Es una referencia que apunta al objeto.
Los métodos miembro se declaran dentro de la declaración de la clase, tal como se ha visto en el capítulo anterior. Por ejemplo:
class Circulo { Punto centro; // dato miembro. Referencia a un objeto punto int radio; // dato miembro. Valor primitivo float superficie() { // método miembro. return 3.14 * radio * radio; } / / fin del método superficie } / / fin de la clase Circulo
El acceso a métodos miembros es igual que el que ya se ha visto para datos miembro. En el ejemplo:
Circulo c = new Circulo(); c.centro.x = 2; c.centro.y = 3; c.radio = 5; float s = c.superficie();
Es interesante observar en el ejemplo:
Desde un constructor puede invocarse explicitamente a otro constructor utilizando la palabra reservada this. this es una referencia al propio objeto. Cuando this es seguido por parénteses se entiende que se está invocando al constructor del objeto en cuestión. Puedes ver el uso más habitual de this aquí. El ejemplo anterior puede reescribirse de la siguiente forma:
class Punto { int x , y ; Punto ( int a , int b ) { x = a ; y = b ; } Punto () { this (0,0); } }
Cuando se declaran varios constructores para una misma clase estos deben distinguirse en la lista de argumentos, bien en el número, bien en el tipo.
Esta característica de definir métodos con el mismo nombre se denomina sobrecarga y es aplicable a cualquier método miembro de una clase como veremos más adelante.
Un dato estático es una variable miembro que no se asocia a un objeto (instancia) de una clase, sino que se asocia a la clase misma; no hay una copia del dato para cada objeto sino una sola copia que es compartida por todos los objetos de la clase.
Por ejemplo:
class Punto { int x , y ; static int numPuntos = 0;
Punto ( int a , int b ) { x = a ; y = b; numPuntos ++ ; } }
En el ejemplo numPuntos es un contador que se incrementa cada vez que se crea una instancia de la clase Punto.
Observese la forma en que se declara numPuntos, colocando el modificador static delante del tipo. La sintaxis general para declarar una variable es:
[ modificadores ] tipo_variable nombre ;
static es un modificador. En los siguientes capítulos se irán viendo otros modificadores. Los [ ] en la expresión anterior quieren decir que los modificadores son opcionales.
El acceso a las variables estáticas desde fuera de la clase donde se definen se raliza a través del nombre de la clase y no del nombre del objeto como sucede con las variables miembro normales (no estáticas). En el ejemplo anterior puede escribirse:
int x = Punto.numPuntos;
No obstante también es posible acceder a las variables estáticas a través de una referencia a un objeto de la clase. Por ejemplo:
Punto p = new Punto(); int x = p.numPuntos;
Las variables estáticas de una clase existen, se inicializan y pueden usarse antes de que se cree ningún objeto de la clase.
Para los métodos, la idea es la misma que para los datos: los métodos estáticos se asocian a una clase, no a una instancia.
Por ejemplo:
class Punto { int x , y ; static int numPuntos = 0;
Punto ( int a , int b ) { x = a ; y = b; numPuntos ++ ; }
static int cuantosPuntos() { return numPuntos; } }
La sintaxis general para la definición de los métodos es, por tanto, la siguiente:
[modificadores ]^ Tipo_Valor_devuelto nombre_método ( lista_argumentos ) { bloque_de_codigo; }
El aceso a los métodos estáticos se hace igual que a los datos estáticos, es decir, usando el nombre de la clase, en lugar de usar una referencia:
int totalPuntos = Punto.cuantosPuntos();
Dado que los métodos estáticos tienen sentido a nivel de clase y no a nivel de objeto (instancia) los métodos estáticos no pueden acceder a datos miembros que no sean estáticos.
Un programa Java se inicia proporcionando al intérprete Java un nombre de clase. La JVM carga en memoria la clase indicada e inicia su ejecución por un método estático que debe estar codificado en esa clase. El nombre de este método es main y debe declararse de la siguiente forma:
static void main ( String [] args)
No es obligatorio que todas las clases declaren un método main. Sólo aquellos métodos que vayan a ser invocados directamente desde la línea de comandos de la JVM necesitan tenerlo. En la práctica la mayor parte de las clases no lo tienen.
En ocasiones es necesario escribir código para inicializar los datos estáticos, quizá creando algún otro objeto de alguna clase o realizando algún tipo de control. El fragmento de código que realiza esta tarea se llama inicializador estático. Es un bloque de sentencias que no tiene nombre, ni recibe argumentos, ni devuelve valor. Simplemente se declara con el modificador static.
La forma de declarar el inicializador estático es:
static { bloque_codigo }
Por ejemplo:
class Punto { int x , y ; static int numPuntos;
recuperación de espacio en memoria se denomina 'recogida de basura' y es descrita un poco más adelante .
El ámbito de las variables locales es el bloque de código donde se declaran. Fuera de ese bloque la variable es desconocida.
Ejemplo:
{ int x; // empieza el ámbito de x. (x es conocida y utilizable) { int q; // empieza el ámbito de q. x sigue siendo conocida.
... } // finaliza el ámbito de q (termina el bloque de código) ... // q ya no es utilizable } // finaliza el ámbito de x
Cuando ya no se necesita un objeto simplemente puede dejar de referenciarse. No existe una operación explícita para 'destruir' un objeto o liberar el área de memoria usada por él.
La liberación de memoria la realiza el recolector de basura ( garbage collector ) que es una función de la JVM. El recolector revisa toda el área de memoria del programa y determina que objetos pueden ser borrados porque ya no tienen referencias activas que los apunten. El recolector de basura actua cuando la JVM lo determina (tiene un mecanismo de actuación no trivial).
En ocasiones es necesario realizar alguna acción asociada a la acción de liberar la memoria asignada al objeto (como por ejemplo liberar otros recursos del sistema, como descriptores de ficheros). Esto puede hacerse codificando un método finalize que debe declararse como:
protected void finalize() throws Throwable { }
Nota: las clausulas protected y throws se explican en capítulos posteriores.
El método finalize es invocando por la JVM antes de liberar la memoria por el recolector de basura, o antes de terminar la JVM. No existe un momento concreto en que las áreas de memoria son liberadas, sino que lo determina en cada momento la JVM en función de sus necesidades de espacio.
Una misma clase puede tener varios métodos con el mismo nombre siempre que se diferencien en el tipo o número de los argurmentos. Cuando esto sucede se dice que el método está sobrecargado. Por ejemplo, una misma clase podría tener los métodos:
int metodoSobrecargado() {.. .} int metodoSobrecargado( int x) {.. .}
Sin embargo no se puede sobrecargar cambiando sólo el tipo del valor devuelto. Por ejemplo: int metodoSobrecargado() {.. .} void metodoSobrecargado() {.. .} // error en compilación
con esta definición, en la expresión y.metodoSobrecargado() la JVM no sabría que método invocar.
Se puede sobrecargar cualquier método miembro de una clase, así como el constructor.
En ocasiones es conveniente disponer de una referencia que apunte al propio objeto que se está manipulando. Esto se consigue con la palabra reservada this. this es una referencia implicita que tienen todos los objetos y que apunta a si mismo. Por ejemplo:
class Circulo { Punto centro; int radio;
Circulo elMayor(Circulo c) { if (radio > c.radio) return this ; else return c; } } El método elMayor devuelve una referencia al círculo que tiene mayor radio, comparando los radios del Circulo c que se recibe como argumento y el propio. En caso de que el propio resulte mayor el método debe devolver una referencia a si mismo. Esto se consigue con la expresión return this.
Para asignar a una referencia el valor nulo se utiliza la constante null. El ejemplo del caso anterior se podría completar con:
class Circulo { Punto centro; int radio;
... Circulo elMayor(Circulo c) { if (radio > c.radio) return this ; else if (c.radio > radio) return c; else return null; } }
Puede ocurrir que una variable local y una variable miembro reciban el mismo nombre (en muchos casos por error). Cuando se produce esto la variable miembro queda oculta por la variable local, durante el bloque de código en que la variable local existe y es accesible. Cuando se sale fuera del ámbito de la variable local, entonces la variable miembro queda accesible. Observese esto en el ejemplo siguiente:
... String x = "Variable miembro"; ... void variableOculta() { System.out.println(x); { String x = "Variable local"; System.out.println(x); } System.out.println(x); }
Nota: El uso de Strings se verá en un capítulo posterior, aunque su uso aquí resulta bastante intuitivo. La llamada System.out.println envia a la consola (la salida estándar habitual) las variables que se pasan como argumentos.
La llamada al método variableOculta() producirá la siguiente salida:
Variable miembro Variable local Variable miembro
Se puede acceder a la variable miembro oculta usando la referencia this. En el ejemplo anterior la expresión:
System.out.println(this.x);
siempre producirá la salida 'Variable miembro', puesto que this.x se refiere siempre a la variable miembro.
La siguiente tabla muestra un resumen de operadores clasificados por grupos:
Sintaxis formato 1:
while (expresion_booleana) sentencia
Sintaxis formato 2:
do sentencia while (expresion_booleana)
La sentencia o bloque se sentencias (se aplica la misma idea que para el if-else) se ejecuta mientras que la expresion_booleana se evalue como true
La diferencia entre ambos formatos es que en el primero la expresión se evalua al principio del bloque de sentencias y en el segundo se evalua al final.
El formato es:
for ( inicializacion ; expresion_booleana ; step ) sentencia
inicializacion es una sentencia que se ejecuta la primera vez que se entra en el bucle for. Normalmente es una asignación. Es opcional.
expresion_booleana es una expresión que se evalua antes de la ejecución de la sentencia, o bloque de sentencias, para cada iteración. La sentencia o bloque de sentencias se ejecutan mientras que la expresion_booleana se evalue como cierta. Es opcional.
step es una sentencia que se ejecuta cada vez que se llega al final de la sentencia o bloque de sentencias. Es opcional.
Una utilización clásica de un bucle de tipo for se muestra a continuación para evaluar un contador un número fijo de veces:
for ( int i = 1 ; i <= 10 ; i++ ) sentencia
La sentencia (o bloque de sentencias) se evaluará 10 veces. En cada ejecución (pasada) el valor de la variable i irá variando desde 1 hasta 10 (inclusive). Cuando salga del bloque de sentencias i estará fuera de su ámbito (porque se define en el bloque for).
Si se omiten las tres clausulas del bucle se obtiene un bucle infinito:
for ( ; ; ) sentencia
Obsérvese que se pueden omitir las clausulas pero no los separadores (;).
El formato es:
switch ( expresion_entera ) { case valor_entero: sentencia; break ; case valor_entero: sentencia; break ;
... default : sentencia; }
Cuidado: en el switch la expresión que se evalua no es una expresión booleana como en el if-else, sino una expresión entera.
Se ejecuta el bloque case cuyo valor coincida con el resultado de la expresión entera de la clausula switch. Se ejecuta hasta que se encuentra una sentencia break o se llega al final del switch.
Si ningún valor de case coincide con el resultado de la expresión entera se ejecuta el bloque default (si está presente).
default y break son opcionales.
El formato es:
return valor
Se utiliza en los métodos para terminar la ejecución y devolver un valor a quien lo llamó.
valor debe ser del tipo declarado en el método.
valor es opcional. No debe existir cuando el método se declara de tipo void. En este caso, la claúsula return al final del método es opcional, pero puede usarse para devolver el control al llamador en cualquier momento.
La mayor parte del trabajo en un programa se hace mediante la evaluación de expresiones, bien por sus efectos tales como asignaciones a variables, bien por sus valores, que pueden ser usados como argumentos u operandos en expresiones mayores, o afectar a la secuencia de ejecución de instrucciones.
Cuando se evalua una expresión en un programa el resultado puede denotar una de tres cosas:
Si la expresión denota una variable o un valor, entonces la expresión tiene siempre un tipo conocido en el momento de la compilación. Las reglas para determinar el tipo de la expresión varían dependiendo de la forma de las expresiones pero resultan bastante naturales. Por ejemplo, en una expresión aritmética con operandos de diversas precisiones el resultado es de un tipo tal que no se produzca pérdida de información, realizandose internamente las conversiones necesarias. El análisis pormenorizado de las conversiones de tipos, evaluaciones de expresiones, etc, queda fuera del ámbito de estos apuntes. En general puede decirse que es bastante similar a otros lenguajes, en particular C, teniendo en cuenta la característica primordial de Java de tratarse de un lenguaje con control fuerte de tipos.
Un array es una colección ordenada de elementos del mismo tipo, que son accesibles a través de un índice.
Un array puede contener datos primitivos o referencias a objetos.
Los arrays se declaran:
[ modificadores ] tipo_variable [ ] nombre ;
Por ejemplo:
int [ ] a; Punto [ ] p;
La declaración dice que a es un array de enteros y p un array de objetos de tipo Punto. Más exactamente a es una referencia a una colección de enteros, aunque todavía no se sabe cuantos elementos tiene el array. p es una referencia a una colección de referencias que apuntarán objetos Punto.
Un array se crea como si se tratara de un objeto (de hecho las variables de tipo array son referencias):
a = new int [5]; p = new Punto[3];
En el momento de la creación del array se dimensiona el mismo y se reserva la memoria necesaria.
Sin embargo también es posible crear un String directamente, sin usar el operador new, haciendo una asignación simple (como si se tratara de un dato primitivo): String s = "Esto es una cadena de caracteres";
Ambas expresiones conducen al mismo objeto. Los Strings no se modifican una vez que se les ha asignado valor. Si se produce una reasignación se crea un nuevo objeto String con el nuevo contenido. Además la clase String proporciona constructores para crear Strings a partir de arrays de caracteres y arrays de bytes. Consultar la documentación del API del JDK para más detalles.
Java define el operador + (suma) con un significado especial cuando las operandos son de tipo String. En este caso el operador suma significa concatenación. El resultado de la concatenación es un nuevo String compuesto por las dos cadenas, una tras otra. Por ejemplo: String x = "Concatenar" + "Cadenas"; da como resultado el String "ConcatenarCadenas".
También es posible concatenar a un String datos primitivos, tanto numéricos como booleanos y char. Por ejemplo, se puede usar: int i = 5; String x = "El valor de i es " + i;
Cuando se usa el operador + y una de las variables de la expresión es un String, Java transforma la otra variable (si es de tipo primitivo) en un String y las concatena. Si la otra variable es una referencia a un objeto entonces invoca el método toString() que existe en todas las clases (es un método de la clase Object).
La clase String dispone de una amplia gama de métodos para la manipulación de las cadenas de caracteres. Para una referencia completa consultar la documentación del API del JDK. El siguiente cuadro muestra un resumen con algunos de los métodos más significativos:
Método Descripción
char charAt(int index) (^) Devuelve el carácter en la posición indicada por index. El rango de index va de 0 a length() - 1. boolean equals(Object obj) (^) Compara el String con el objeto especificado. El resultado es true si y solo si el argumento es no nulo y es un objeto String que contiene la misma secuencia de caracteres.
boolean equalsIgnoreCase (String s)
Compara el String con otro, ignorando consideraciones de mayúsculas y minúsculas. Los dos Strings se consideran iguales si tienen la misma longitud y, los caracteres correspondientes en ambos Strings son iguales sin tener en cuenta mayúsculas y minúsculas.
int indexOf(char c) Devuelve el indice donde se produce la primera aparición de c. Devuelve -1 si c no está en el string. int indexOf(String s) (^) Igual que el anterior pero buscando la subcadena representada por s.
int length() Devuelve la longitud del String (número de caracteres)
String substring(int begin, int end)
Devuelve un substring desde el índice begin hasta el end
static String valueOf(int i) (^) Devuelve un string que es la representación del entero i. Observese que este método es estático. Hay métodos equivalentes donde el argumento es un float, double, etc. char[] toCharArray() String toLowerCase() String toUpperCase()
Transforman el string en un array de caracteres, o a mayúsculas o a minúsculas.
Dado que la clase String sólo manipula cadenas de caracteres constantes resulta poco conveniente cuando se precisa manipular intensivamente cadenas (reemplazadno caracteres, añadiendo o suprimiendo, etc.). Cuando esto es necesario puede usarse la clase StringBuffer definida también en el package java.lang. del API. Esta clase implanta un buffer dinámico y tiene métodos que permiten su manipulación comodamente. Ver la documentación del API.
Un package es una agrupación de clases afines. Equivale al concepto de librería existente en otros lenguajes o sistemas. Una clase puede definirse como perteneciente a un package y puede usar otras clases definidas en ese o en otros packages.
Los packages delimitan el espacio de nombres (space name). El nombre de una clase debe ser único dentro del package donde se define. Dos clases con el mismo nombre en dos packages distintos pueden coexistir e incluso pueden ser usadas en el mismo programa.
Una clase se declara perteneciente a un package con la clausula package, cuya sintaxis es:
package nombre_package;
La clausula package debe ser la primera sentencia del archivo fuente. Cualquier clase declarada en ese archivo pertenece al package indicado.
Por ejemplo, un archivo que contenga las sentencias:
package miPackage;
... class miClase { ...
declara que la clase miClase pertenece al package miPackage.
La claúsula package es opcional. Si no se utiliza, las clases declaradas en el archivo fuente no pertenecen a ningún package concreto, sino que pertenecen a un package por defecto sin nombre.
La agrupación de clases en packages es conveniente desde el punto de vista organizativo, para mantener bajo una ubicación común clases relacionadas que cooperan desde algún punto de vista. También resulta importante por la implicación que los packages tienen en los modificadores de acceso, que se explican en un capítulo posterior.
Cuando se referencia cualquier clase dentro de otra se asume, si no se indica otra cosa, que ésta otra está declarada en el mismo package. Por ejemplo:
package Geometria;
... class Circulo { Punto centro; ... }
En esta declaración definimos la clase Circulo perteneciente al package Geometria. Esta clase usa la clase Punto. El compilador y la JVM asumen que Punto pertenece también al package Geometria, y tal como está hecha la definición, para que la clase Punto sea accesible (conocida) por el compilador, es necesario que esté definida en el mismo package.
Si esto no es así, es necesario hacer accesible el espacio de nombres donde está definida la clase Punto a nuestra nueva clase. Esto se hace con la clausula import. Supongamos que la clase Punto estuviera definida de esta forma:
package GeometriaBase; class Punto { int x , y; }
Entonces, para usar la clase Punto en nuestra clase Circulo deberiamos poner:
package GeometriaAmpliada;
Nota: Los modificadores de acceso se explicarán detalladamente en un capítulo posterior.
Si una clase no se declara public sólo puede ser usada por clases que pertenezcan al mismo package.
En este apartado se asume que se ha instalado el JDK (J2SE) distribuido por SUN Microsystems y que tanto el compilador (javac) como la JVM (java) están accesibles. Asumiremos que los comandos se emitirán desde una ventana DOS en un sistema Windows, siendo la sintaxis en un entorno UNIX muy parecida. En este capítulo se verán todos los pasos necesarios para crear, compilar y ejecutar un programa Java.
PASO 1: Con un editor de texto simple (incluso notepad sirve, aunque resulta poco aconsejabe) creamos un archivo con el contenido siguiente:
package Programas.Ejemplo1;
class HolaMundo { public static void main ( String [] args) { System.out.println("Hola a todos"); } }
Guardamos el fichero fuente con nombre HolaMundo.java en la carpeta: C:\ApuntesJava \Programas\Ejemplo1.
PASO 2: Abrimos una ventana DOS y en ella:
C:> cd C:\ApuntesJava C:\ApuntesJava>javac Programas\Ejemplo \HolaMundo.java
Si no hay ningún error en el programa se producirá la compilación y el compilador almacenará en el directorio C:\ApuntesJava\Programas\Ejemplo1 un fichero de nombre HolaMundo.class, con el código ejecutable correspondiente a la clase HolaMundo.
Recuerda que en Java las mayúsculas y minúsculas son significativas. No es lo mismo la clase ejemplo que la clase Ejemplo1. Esto suele ser fuente de errores, sobre todo al principio. Sin embargo, ten en cuenta que en algunos sistemas operativos como Windows, o más concretamente en una ventana DOS, esta distinción no existe. Puedes poner cd C:\ApuntesJava o cd C:\APUNTESJAVA indistintamente: el resultado será el mismo (no así en cualquier UNIX, que sí distingue unas y otras). Asegurate por tanto, de que las palabras están correctamente escritas.
Cuando pones javac Programas\Ejemplo1\HolaMundo.java estás indicando al compilador que busque un archivo de nombre HolaMundo.java en la ruta Programas\Ejemplo1, a partir del directorio actual; es decir, estás especificando la ruta de un archivo.
En el ejemplo se utiliza la clase del API de Java System. Sin embargo el programa no tiene ningún import. No obstante el compilador no detecta ningún error y genera el código ejecutable directamente. Esto se debe a que la clase System está definida en el package java.lang, que es el único del que no es necesario hacer el import , que es hecho implicitamente por el compilador. Para cualquier clase del API, definida fuera de este package es necesario hacer el impor correspondiente.
PASO 3: Ejecutar el programa: Desde la ventana DOS.
C:\ApuntesJava>java Programas.Ejemplo1.HolaMundo
Se cargará la JVM, cargará la clase HolaMundo y llamará a su método main que producirá en la ventana DOS la salida:
Hola a todos
Los archivos .class son invocables directamente desde la línea de comandos (con la sintaxis java nombreDeClase) si tienen un método main definido tal como se vio en un capítulo anterior.
Se puede indicar a la JVM que busque las clases en rutas alternativas al directorio actual. Esto se hace con el parámetro -classpath (abreviadamente -cp) en la línea de comandos. Por ejemplo si el directorio actual es otro, podemos invocar el programa de ejemplo de la forma:
C:\Windows>java -cp C:\ApuntesJava Programas.Ejemplo1.HolaMundo
Con el parámetro -cp se puede especificar diversas rutas alternativas para la búsqueda de clases separadas por ;
Cuando pones java Programas.Ejemplo1.HolaMundo estás indicando a la JVM que cargue y ejecute la clase HolaMundo del Package Programas, subpackage Ejemplo1. Para cumplir está orden, expresada en términos Java de clases y packages la JVM buscará el archivo HolaMundo.class en la ruta Programas\Ejemplo1 que es algo expresado en términos del sistema de archivos, y por tanto del Sistema Operativo.
El esquema habitual es tener un archivo fuente por clase y asignar al archivo fuente el mismo nombre que la clase con la extensión .java (el nombre .java para la extensión es obligatorio). Esto generará al compilar un archivo .class con el mismo nombre que el fuente ( y que la clase). Fuentes y módulos residirán en el mismo directorio.
Lo habitual es tener uno o varios packages que compartan un esquema jerárquico de directorios en función de nuestras necesidades (packages por aplicaciones, temas, etc.)
Es posible definir más de una clase en un archivo fuente, pero sólo una de ellas podrá ser declarada public (es decir podrá ser utilizada fuera del package donde se define). Todas las demás clases declaradas en el fuente serán internas al package. Si hay una clase public entonces, obligatoriamente, el nombre del fuente tiene que coincider con el de la clase declarada como public. Los modificadores de acceso (public, es uno de ellos) se verán en el capítulo siguiente.13. Modificadores de acceso
Los modificadores son elementos del lenguaje que se colocan delante de la definición de variables locales, datos miembro, métodos o clases y que alteran o condicionan el significado del elemento. En capítulos anteriores se ha descrito alguno, como es el modificador static que se usa para definir datos miembros o métodos como pertenecientes a una clase, en lugar de pertenecer a una instancia. En capítulos posteriores se tratarán otros modificadores como final , abstract o synchronized. En este capítulo se presentan los modificadores de acceso, que son aquellos que permiten limitar o generalizar el acceso a los componentes de una clase o a la clase en si misma.
Los modificadores de acceso permiten al diseñador de una clase determinar quien accede a los datos y métodos miembros de una clase.
Los modificadores de acceso preceden a la declaración de un elemento de la clase (ya sea dato o método), de la siguiente forma:
[ modificadores ] tipo_variable nombre ; [ modificadores ] tipo_devuelto nombre_Metodo ( lista_Argumentos ) ;
Existen los siguientes modificadores de acceso:
Pueden utilizarse estos modificadores para cualquier tipo de miembros de la clase, incluidos los constructores (con lo que se puede limitar quien puede crear instancias de la clase).