Entradas populares

domingo, 7 de junio de 2015

Clases

La definición de una clase especifica cómo serán los objetos de dicha clase, esto es, de que variables y de que métodos constarán.
La siguiente es la definición más simple de una clase:
   class nombreClase     /* Declaración de la clase */
   {
  
      /* Aquí va la definición de variables y métodos */
      
   }

Como se puede observar, la definición de una clase consta de dos partes fundamentales: 

* La declaración de la clase 

Indica el nombre de la clase precedido por la palabra clave class

* El cuerpo de la clase 
El cuerpo de la clase sigue a la declaración de la clase y está contenido entre la pareja de llaves ({ y }). El cuerpo de la clase contiene las declaraciones de las variables de la clase, y también la declaración y la implementación de los métodos que operan sobre dichas variables.

  • Declaración de variables de instancia 

    El estado de un objeto está representado por sus variables (variables de instancia). Las variables de instancia se declaran dentro del cuerpo de la clase. Típicamente, las variables de instancia se declaran antes de la declaración de los métodos, pero esto no es necesariamente requerido. 

  • Implementación de métodos 
Los métodos de una clase determinan los mensajes que un objeto puede recibir.

Las partes fundamentales de un método son el valor de retorno, el nombre, los argumentos (opcionales) y su cuerpo. Además, un método puede llevar otros modificadores opcionales que van al inicio de la declaración del método y que se analizarán más adelante. La sintaxis de un método es la siguiente: 
   <otrosModificadores>  valorRetorno  nombreMetodo( <lista de argumentos> )
   {
      /* Cuerpo del método */
      sentencias;
   }



   Los signos <> indican que no son obligatorios.
Los métodos en Java pueden ser creados únicamente como parte de una clase. Cuando se llama a un método de un objeto se dice comúnmente que se envia un mensaje al objeto.

Ejemplo

/* Usuario.java */

class Usuario
{
     String nombre;
     int edad;
     String direccion;                    

     void setNombre(String n)
     {
        nombre = n;
     }
    
     String getNombre()
     {
        return nombre;
     }
    
     void setEdad(int e)
     {
        edad = e;
     }

     int getEdad()
     {
        return edad;
     }
    
     void setDireccion(String d)
     {
        direccion = d;
     }

     String getDireccion()
     {
        return direccion;
     }
}


Constructores y creación de objetos 

Una vez que se tiene definida la clase a partir de la cual se crearán los objetos se está en la posibilidad de instanciar los objetos requeridos. 

Para la clase Usuario del ejemplo anterior podemos crear un objeto de la siguiente manera: 

Usuario usr1;     //usr1 es una variable del tipo Usuario
usr1 = new Usuario();
La primera línea corresponde a la declaración del objeto, es decir, se declara una variable del tipo de objeto deseado.

La segunda línea corresponde a la iniciación del objeto.
  • El operador new 
El operador new crea una instancia de una clase asignando la cantidad de memoria necesaria de acuerdo al tipo de objeto. El operador new se utiliza en conjunto con un constructor. El operadornew regresa una referencia a un nuevo objeto. 
  • Constructores 
Un constructor es un tipo específico de método que siempre tiene el mismo nombre que la clase, y que se utiliza cuando se desean crear objetos de dicha clase, es decir, se utiliza al crear e iniciar un objeto de una clase. 
  • Constructores múltiples 
Cuando se declara una clase en Java, se pueden declarar uno o más constructores (constructores múltiples) opcionales que realizan la iniciación cuando se instancia un objeto de dicha clase.
Para la clase Usuario del ejemplo anterior no se especificó ningún constructor, sin embargo, Java proporciona un constructor por omisión que inicia las variables del objeto a sus valores predeterminados. 

Ej.

/* ProgUsuario.java */

class ProgUsuario
{
   public static void main(String args[])
   {
     Usuario usr1, usr2;     /* Se declaran dos objetos de la clase Usuario */
     boolean si_no;
              
     usr1 = new Usuario();       /* Se utiliza el constructor por omisión */
     si_no = usr1 instanceof Usuario;
              
     if(si_no == true)
       System.out.println("\nEl objeto usr1 SI es instancia de Usuario.");
     else
       System.out.println("\nEl objeto usr1 NO es instancia de Usuario.");
              
     usr2 = usr1;              /* usr1 y usr2 son el mismo objeto */
     si_no = usr2 instanceof Usuario;
              
     if(si_no == true)
       System.out.println("\nEl objeto usr2 SI es instancia de Usuario.");
     else
       System.out.println("\nEl objeto usr2 NO es instancia de Usuario.");
    }
}


Main ()
El método Main ()
Cada aplicación de C# debe contener un método Main único, que especifique dónde debe comenzar la ejecución del programa. En C#,Main se pone en mayúsculas, mientras que Java utiliza main en minúscula.
Main puede devolver sólo int o void y tiene un argumento de matriz de cadena opcional para representar parámetros de línea de comandos:
C#
static int Main(string[] args)
{
    //...
    return 0;
}


El parámetro de matriz de cadena, que contiene todos los argumentos de la línea de comandos pasados, funciona igual que en Java. Así, args[0] especifica el primer parámetro de línea de comandos, args[1] denota el segundo parámetro, etc. A diferencia de C++, la matriz args no contiene el nombre del archivo EXE.
Cuando se pasan parámetros a un método, se pueden pasar por valor o por referencia. Los parámetros de valor simplemente toman el valor de cualquier variable para utilizarlo en el método. Por lo tanto, el valor de variable en el código de llamada no se ve afectado por las acciones realizadas en los parámetros de un método.
Sin embargo, los parámetros de referencia apuntan a una variable declarada en el código de llamada; por lo tanto, los métodos modificarán el contenido de esa variable cuando se pase por referencia.
En Java y C#, los parámetros de método que hacen referencia a un objeto siempre se pasan por referencia, mientras que los parámetros de tipo de datos primitivo (tipos de valor en C#) se pasan por valor.
En C#, para pasar un tipo de valor por referencia, debe especificar una de las palabras clave ref o out. La diferencia entre estas dos palabras clave radica en la inicialización de los parámetros. Un parámetro ref se debe inicializar antes de su utilización, mientras que un parámetro out no debe inicializarse explícitamente sin que antes se haya pasado por referencia y se haya omitido cualquier valor anterior.
Especifique esta palabra clave en un parámetro de tipo de valor cuando desee que el método llamado cambie permanentemente el valor de las variables utilizadas como parámetros. De esta manera, en lugar de pasar el valor de una variable utilizada en la llamada, se pasa una referencia a la propia variable. Entonces el método funciona en la referencia, de modo que los cambios realizados al parámetro durante la ejecución del método se conservan en la variable original utilizada como parámetro para el método.
El código siguiente muestra un ejemplo de esto en el método Add, donde el segundo parámetro int se pasa por referencia con la palabra clave ref:
C#
class TestRef
{
    private static void Add(int i, ref int result)
    {
        result += i;
        return;
    }

    static void Main()
    {
        int total = 20;
        System.Console.WriteLine("Original value of 'total': {0}", total);

        Add(10, ref total);
        System.Console.WriteLine("Value after calling Add(): {0}", total);
    }
}



El resultado de este sencillo ejemplo demuestra que los cambios realizados al parámetro resultante se reflejan en la variable total, utilizada en la llamada al método Add :
Original value of 'total': 20
Value after calling Add(): 30
Esto se debe a que el parámetro resultante hace referencia a la ubicación de memoria real que ocupa la variable total en el código de llamada. Una propiedad de una clase no es una variable; por lo tanto, no se puede utilizar directamente como parámetro ref.
La palabra clave ref debe preceder al parámetro cuando se llama al método, al igual que en la declaración de método.
La palabra clave out tiene un efecto muy similar a la palabra clave ref. Las modificaciones realizadas a un parámetro declarado que utiliza out serán visibles fuera del método. Las dos diferencias con respecto a ref son que todo valor inicial de un parámetro out se omite dentro del método y que un parámetro out se debe asignar durante la ejecución del método:
C#
class TestOut
{
    private static void Add(int i, int j, out int result)
    {
        // The following line would cause a compile error:
        // System.Console.WriteLine("Initial value inside method: {0}", result);

        result = i + j;
        return;
    }

    static void Main()
    {
        int total = 20;
        System.Console.WriteLine("Original value of 'total': {0}", total);

        Add(33, 77, out total);
        System.Console.WriteLine("Value after calling Add(): {0}", total);
    }
}


En este caso, el tercer parámetro para el método Add se declara con la palabra clave out y las llamadas al método también necesitan la palabra clave out para ese parámetro. El resultado será:
Original value of 'total': 20
Value after calling Add(): 110
Por lo tanto utilice la palabra clave ref cuando desee que un método modifique una variable existente y utilice la palabra clave out, para devolver un valor generado dentro del método. Generalmente, esto se utiliza junto con el valor que el método devuelve cuando éste genera más de un valor resultante para el código de llamada.




viernes, 5 de junio de 2015

Declaración de variables y constantes

Variables Miembro
Una clase en Java puede contener variables y métodos. Las variables pueden ser tipos primitivos como int, char, etc. Los métodos son funciones.
Por ejemplo, en el siguiente trozo de código podemos observarlo:

               public class MiClase {
                  int i;

               public MiClase() {
                 i = 10;
                }
              public void Suma_a_i( int j ) {
                 int suma;
               suma = i + j;
              }
           }

La clase MiClase contiene una variable (i) y dos métodos, MiClase() que es el constructor de la clase y Suma_a_i( int j ).
La declaración de una variable miembro aparece dentro del cuerpo de la clase, pero fuera del cuerpo de cualquier método de esa clase. Si se declara dentro de un métodos, será una variable local del método y no una variable miembro de la clase. En el ejemplo anterior, i es una variable miembro de la clase y suma es una variable local del método Suma_ a_i().
El tipo de una variable determina los valores que se le pueden asignar y las operaciones que se pueden realizar con ella.
El nombre de una variable ha de ser un identificador válido en Java. Por convenio, los programadores Java empiezan los nombres de variables con una letra minúscula, pero no es imprescindible. Los nombres de las variables han de ser únicos dentro de la clase y se permite que haya variables y métodos con el mismo nombre, a diferencia de C++, en donde se produce un error de compilación si se da este caso.
Para los programadores C++, se pueden señalar algunas diferencias entre Java y C++ respecto a la sintaxis e interpretación en la declaración de variables miembro de una clase, como son:
  • En los dos lenguajes se permite la declaración de variables miembro estáticas con una sintaxis parecida, aunque en C++, se deben redeclarar estas variables fuera de la definición de la clase utilizando el nombre de la clase, el nombre de la variable y el operador de ámbito
  • En los dos lenguajes se permite la utilización de modificadores de acceso a las variables miembro utilizando las palabras clave public, private y protected, aunque la sintaxis e interpretación son diferentes en los dos lenguajes
  • Los dos lenguajes reconocen la palabra clave volatile, aunque Java la ignora
  • C++ no reconoce las palabras clave transient y final, utilizadas en la declaración de variables miembro en Java.

Aparte de las diferencias de sintaxis anteriores, Java permite la inicialización de variables miembro de tipos primitivos en el momento de la declaración y esto no es posible en C++.
La sintaxis completa de la declaración de una variable miembro de una clase en Java sería:
[especificador_de_acceso][static][final][transient][volatile]
    tipo nombreVariable [= valor_inicial];

Ambito de una Variable
Los bloques de sentencias compuestas en Java se delimitan con dos llaves. Las variables de Java sólo son válidas desde el punto donde están declaradas hasta el final de la sentencia compuesta que la engloba. Se pueden anidar estas sentencias compuestas, y cada una puede contener su propio conjunto de declaraciones de variables locales. Sin embargo, no se puede declarar una variable con el mismo nombre que una de ámbito exterior.
El siguiente ejemplo intenta declarar dos variables separadas con el mismo nombre. En C y C++ son distintas, porque están declaradas dentro de ámbitos diferentes. En Java, esto es ilegal.

         class Ambito {
               int i = 1;     // ámbito exterior
            {              // crea un nuevo ámbito
               int i = 2; // error de compilación
            }
       }

Variables de Instancia
La declaración de una variable miembro dentro de la definición de una clase sin anteponerle la palabra clave static, hace que sea una variable de instancia en todos los objetos de la clase. El significado de variable de instancia sería, más o menos, que cualquier objeto instanciado de esa clase contiene su propia copia de toda variable de instancia. Si se examinara la zona de memoria reservada a cada objeto de la clase, se encontraría la reserva realizada para todas las variables de instancia de la clase. En otras palabras, como un objeto es una instancia de una clase, y como cada objeto tiene su propia copia de un dato miembro particular de la clase, entonces se puede denominar a ese dato miembro como variable de instancia.
En Java, se accede a las variables de instancia asociadas a un objeto determinado utilizando el nombre del objeto, el operador punto (.) y el nombre de la variable:
  miObjeto.miVariableDeInstancia;
En C++, se puede acceder a las variables de instancia de un objeto a través de la misma sintaxis, pero también utilizando el operador flecha (->), que utiliza como origen una variable puntero que apunta al objeto:
    miVariablePuntero->miVariableDeInstancia;


Variables Estáticas
La declaración de un dato miembro de una clase usando static, crea una variable de clase o variable estática de la clase. El significado de variable estática es que todas las instancias de la clase (todos los objetos instanciados de la clase) contienen la mismas variables de clase o estáticas. En otras palabras, en un momento determinado se puede querer crear una clase en la que el valor de una variable de instancia sea el mismo (y de hecho sea la misma variable) para todos los objetos instanciados a partir de esa clase. Es decir, que exista una única copia de la variable de instancia, entonces es cuando debe usarse la palabra clave static.

        class Documento extends Pagina {
             static int version = 10;
           }

El valor de la variable version será el mismo para cualquier objeto instanciado de la claseDocumento. Siempre que un objeto instanciado de Documento cambie la variable version, ésta cambiará para todos los objetos.
En C++, es necesario redeclarar todas las variables estáticas fuera de la definición de la clase, produciendo una variable pseudo-global, es decir, una variable que es global en lo que a los objetos de esa clase se refiere.
Si se examinara en este caso la zona de memoria reservada por el sistema para cada objeto, se encontraría con que todos los objetos comparten la misma zona de memoria para cada una de las variables estáticas, por ello se llaman también variables de clase, porque son comunes a la clase, a todos los objetos instanciados de la clase.
Tanto en Java como en C++, se puede acceder a las variables de clase utilizando el nombre de la clase y el nombre de la variable, no es necesario instanciar ningún objeto de la clase para acceder a las variables de clase.
En C++, a las variables de clase se accede utilizando el operador de ámbito junto con el nombre de la clase y el nombre de la variable:
    miVariable::miVariableDeClase;
En Java, a las variables de clase se accede utilizando el nombre de la clase, el nombre de la variable y el operador punto (.). La siguiente línea de código, ya archivista, se utiliza para acceder a la variable out de la clase System. En el proceso, se accede al método println() de la variable de clase que presenta una cadena en el dispositivo estándar de salida.
    System.out.println( "Hola, Mundo" );
Es importante recordar que todos los objetos de la clase comparten las misma variables de clase, porque si alguno de ellos modifica alguna de esas variables de clase, quedarán modificadas para todos los objetos de la clase. Esto puede utilizarse como una forma de comunicación entre objetos.


Constantes
En Java, se utiliza la palabra clave final para indicar que una variable debe comportarse como si fuese constante, significando con esto que no se permite su modificación una vez que haya sido declarada e inicializada.
Como es una constante, se le ha de proporcionar un valor en el momento en que se declare, por ejemplo:

         class Elipse {
               final float PI = 3.14159;
             . . .
           }

Si se intenta modificar el valor de una variable final desde el código de la aplicación, se generará un error de compilación.
Si se usa la palabra clave final con una variable o clase estática, se pueden crear constantes de clase, haciendo de esto modo un uso altamente eficiente de la memoria, porque no se necesitarían múltiples copias de las constantes.

La palabra clave final también se puede aplicar a métodos, significando en este caso que los métodos no pueden ser sobreescritos.