RSS

Archivo de la categoría: Tema 3

El recolector de basura

Muchos lenguajes de programación permiten asignar memoria dinámica en tiempo de ejecución pero es el programador el que tiene la responsabilidad de liberarla.

Sin embargo, Java proporciona un hilo en el nivel del sistema que administra esta memoria, busca la que está en desuso y la libera. Es el recolector de basura o Garbage Collector (GC).

Cuándo se ejecuta:
El GC está bajo el control de la JVM y ella decide cuándo ejecutarlo. Dentro de un programa se puede solicitar la ejecución pero no hay ninguna garantía de que se ejecute.

Cómo funciona:
Los modelos de reciclaje de la memoria pueden variar considerablemente en cada implementación de la JVM. Lo que debemos tener claro es cuándo un objeto es elegible por el GC.

Un objeto es elegible cuando ningún thread vivo puede acceder a él.


Cómo hacer un objeto elegible:

  • Estableciendo la referencia a null:
    Cuando asignamos la referencia de un objeto a null estamos perdiendo cualquier posibilidad de acceder a él.

    public class aNull{
        public static void main (String[] args){
            Integer a = new Integer(10); //1
            a = null; //2
           //ahora el objeto Integer(10) es elegible por el GC.
        }
    }
    

    //1 Creación del objeto.

    //2 La referencia ya no apunta al objeto. La referencia es igual a null. El objeto es ahora elegible por el GC.

  • Reasignando la referencia:
    Cuando hacemos que la referencia que apunta a un objeto apunte a otro distinto dejando el primero inaccesible.

    public class Reasigno{
        public static void main (String[] args){
            Integer a = new Integer(10); //1
            Integer b = new Integer(20); //2
            a = b; //3
            //ahora el objeto Integer(10) es elegible por el GC.
        }
    }
    

    //1 y //2 Creación de los objetos.


    //3 La referencia a y b están ahora apuntando al segundo objeto, siendo el primero elegible para el GC.

  • Cuando la referencia está aíslada:
    Se produce cuando un objeto tiene como miembros otros objetos de su misma clase y aunque se pierdan las referencias de estos objetos aún conservan entre ellos referencias vivas que son elegibles para el GC.

    public class Aislada{
        Aislada vecina;
        public static void main (String[] args){
            Aislada a = new Aislada(); //1
            Aislada b = new Aislada();
    
            a.vecina = b; //2
            b.vecina = c;
            a = null; //3
            b = null; // Aunque las pongamos a null entre los objetos tienen referencias.
        }
     }
    

    //1 y //2: Creación de los objetos Aislada y asignación de la vecina.

       

    //3: Se ponen las referencias a null. Los dos objetos Aisladas son elegibles para el GC.

       

Solicitar la ejecución del GC:
Como hemos dicho antes no se puede forzar la ejecución del recolector de basuras. Se solicita su ejecución mediante la siguiente instrucción pero no se nos garantiza que se ejecute.

Se puede ejecutar mediante:

System.gc();

U obteniendo una instancia de Runtime:

Runtime rt = Runtime.getRuntime();
rt.gc();

Método finalize():
Este método está definido en la clase Object y por tanto todos los objetos lo heredan. En él
podemos escribir cualquier código que queramos que se ejecute antes de que el GC borre el objeto.

Como la ejecución del GC no está garantizada que se ejecute la ejecución de finalize() tampoco está garantizada.

Cada objeto sólo podrá llamar a este método una vez. En este código se podría hacer inelegible el objeto, por ejemplo, volviendo a asignarle una referencia.

 
10 comentarios

Publicado por en 20 octubre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , , , ,

Asignaciones – Sobrecarga de Métodos con Widening, Boxing y Clases Envoltorio

Vamos a ver algunos casos concretos relacionados con el Widening, las Clases Envoltorio y los Argumentos-Variables que pueden hacernos dudar en el momento de saber qué método elije el compilador cuando tenemos métodos sobrecargados…

Sobrecarga y tipos primitivos:

Escogerá el menor tipo que sea mayor que el argumento en la llamada.

class SobrecargaPrimitivos {
    public static void main(String[] args){

        byte byteVar = 10;
        short shortVar = 10;
        char charVar = 10;
        long longVar = 10;
        float floatVar = 10.0f;

        System.out.println ("\nmetodo (byteVar)\u003B");
        metodo (byteVar); //Llamada con un argumento byte

        System.out.println ("\nmetodo (shortVar)\u003B");
        metodo (shortVar); //Llamada con argumento short

        System.out.println ("\nmetodo (charVar)\u003B");
        metodo (charVar); //Llamada con argumento char

        System.out.println ("\nmetodo (longVar)\u003B");
        metodo (longVar); //Llamada con argumento long

        System.out.println ("\nmetodo (floatVar)\u003B");
        metodo (floatVar); //Llamada con argumento float

    }

 static void metodo (int v) { System.out.print ("-> amplia a int y ejecuta metodo (int v) \n");}
 static void metodo (long v) { System.out.print ("-> amplia a long y ejecuta metodo (long v) \n");}
 static void metodo (double v){System.out.print ("-> amplia a double y ejecuta metodo (double v)\n");}

}

Sobrecarga Boxing y tipos primitivos:

Si el compilador tiene que elegir entre hacer un boxing (un método con un parámetro Envoltorio) y un widening (método con un tipo primitivo mayor) elegirá el widening.

class SobrecargaBoxing_Primitivos {
    public static void main (String[] args){
        int intVar = 10;
        System.out.println ("\nmetodo (intVar)\u003B");
        metodo (intVar); // A qué método llamará?
    }

   static void metodo (long v) { System.out.print ("-> amplia a long y ejecuta metodo (long v)\n");}
   static void metodo (Integer v) {System.out.print ("-> boxing a Integer y ejecuta metodo (Integer v)\n");}
}


Sobrecarga Argumentos-Variables y tipos primitivos:  

Si el compilador tiene que elegir entre un método con argumentos variables y un widening (método con un tipo primitivo mayor) elegirá el widening.

class SobrecargaVarArgs_Primitivos {

public static void main (String[] args){

int intVar = 10;

System.out.println ("\nmetodo (intVar)\u003B");
metodo (intVar);

}

 static void metodo (long v) { System.out.print ( "-> amplia a long y ejecuta metodo (long v) \n");}
 static void metodo (int ... v) {System.out.print ( "-> ejecuta metodo (int.. v) \n");}

}


Sobrecarga Boxing y Argumentos-Variables:

Cuando el compilador tiene que elegir entre hacer boxing y un método con argumentos variables, se queda con el boxing.

class SobrecargaBoxing_VarArgs {
public static void main (String[] args){
int intVar = 10;
System.out.println ("\nmetodo (intVar)\u003B");
        metodo (intVar);
}
static void metodo (Integer v) { System.out.print ( "-> boxing a Integer y ejecuta metodo (Integer v) \n");}
  static void metodo (int ... v) {System.out.print ( "-> ejecuta metodo (int.. v) \n");}
}


Sobrecarga y Tipos de Referencia:

El compilador hace widening si encuentra un objeto de una subclase y el método tiene como parámetro un objeto de la superclase. Esto es debido a que un objeto hijo se puede utilizar donde se espera un objeto padre y no al contrario.


Sobrecarga con widening y boxing a la vez:

Veamos qué ocurre en los casos en los que el compilador necesita hacer estas dos conversiones para llamar al método.

  • Amplía y luego Boxing: en este caso el compilador no puede hacer esta operación. Da error de compilación.
public class wideAndBox{
    public static void main(String[] args){
        byte byteVar = 5;
        System.out.println ("\nmetodo (byteVar)\u003B");
        metodo(byteVar);
    }
    static void metodo(Long v){
        System.out.println("-> ejecuta metodo (Long v) \n");
    }
}

El compilador tampoco puede hacer las operaciones cambiando el orden, primero Boxing y luego ampliando  porque un Byte no se puede ampliar a Long (Un Byte no es un Long, no están relacionados por herencia).

  • Boxing y luego amplía: el compilador sí puede hacer estas dos conversiones si despúes de hacer Boxing se puede ampliar porque estén relacionados por herencia. Un Byte es un Object.
public class BoxAndWide{
    public static void main(String[] args){
        byte byteVar = 5;
        System.out.println ("\nmetodo (byteVar)\u003B");
        metodo(byteVar);
    }
    static void metodo(Object  v){
        System.out.println("-> ejecuta metodo (Object v) \n");
    }
}


Combinando Boxing y Widening con VarArgs:

El compilador no tiene problema cuando un método tiene argumentos variables ya haga falta hacer widening o boxing.

public class ejem{

    public static void main(String[] args){
        int entero = 10;
        metodo1 (entero, entero);
        metodo2 (entero, entero);
    }

    static void metodo1(long... v) { System.out.println("metodo(Long... )");}
    static void metodo2(Integer... v) {System.out.println("metodo(Integer... )");}
}


Resumen:

  • Entre diferentes métodos con tipos primitivos, el compilador escoge el menor tipo que sea mayor al argumento de llamada.

En los tres siguientes casos gana la característica más antigua en Java:

  • Entre Boxing y Widening, gana Widening.
  • Entre Args Variables y Widening, gana Widening.
  • Entre Boxing y Argumentos Variables, gana Boxing.
  • Argumentos Variables con Boxing o Argumentos Variables con widening, ambos funcionan.
  • Widening y Boxing, no funciona (int pasaría a long, pero long no puede convertirse en Long).
  • Boxing y Widening, funciona (int pasaría a Integer e Integer puede convertirse en Object).
 
1 comentario

Publicado por en 13 octubre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , , , , ,

Asignaciones – Clases Envoltorio y Boxing

En Java los datos numéricos, de caracteres, lógicos se tratan de forma primitiva por eficiencia.
Normalmente usamos tipos primitivos y no objetos.

Sin embargo, existe una manera de que estos datos puedan ser objetos, usando las llamadas clases envoltorio. Cada tipo primitivo en Java tiene su correspondiente clase envoltorio.

Son las siguientes:

Tipo primitivo Clase envoltorio
boolean Boolean
byte Byte
char Character
short Short
int Integer
long Long
float Float
double Double

Los objetos se construyen pasando el valor al constructor correspondiente.

int entero = 500;
Integer Entero = new Integer(entero); //de primitivo a objeto se llama boxing.
int aEntero = Entero.intValue();            //de objeto a primitivo se llama unboxing.

Muchas veces es útil convertir a estas clases ya que tienen muchos métodos interesantes.

String str = “1000”;
int x = Integer.parseInt(str);

En este último ejemplo hemos podido convertir de String a int utilizando su clase envoltorio Integer y el
método parseInt.

Constructores:

Cada clase envoltorio (menos Character) tienen dos constructores: uno que admite el tipo primitivo como parámetro y otro que admite un String.

Integer a = new Integer(500);
Integer b = new Integer(“500”);

Float c = new Float(7.5f);
Float d = new Float(“7.5f”);

Character e = new Character(‘t’);

Para el constructor Boolean cuando el String es true (sin importar mayúsculas o minúsculas) será true, cualquier otro valor será falso.

Boolean f = new Boolean(false);
Boolean g = new Boolean(“TrUe”); //g será true.

Boolean h = new Boolean (“NO”); //h será false.

ValueOf:

Otra forma de construir un objeto de una clase envoltorio es mediante este método estático, valueOf. Este método puede aceptar un String, o un String y un parámetro que indique la base numérica.

Integer nuevo = new Integer.valueOf(“150”);
Integer binario = new Integer.valueOf(“1010”, 2);

Métodos Útiles:

  • Convierte un Envoltorio en primitivo:
    byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()
  • Convertir un String en primitivo:
    parseByte(), parseShort(), parseInt(), parseLong(), parseFloat(), parseDouble()
  • Dar una representación en String: toString()
  • Convertir números a otras bases. Con objetos Integer y Long se pueden utilizar: toBinaryString(), toOctalString(), toHexString():

Autoboxing y unboxing:

Para pasar de un tipo primitivo a su objeto equivalente se necesita utilizar las clases envoltorio (boxing).
Para obtener de la referencia del objeto su tipo primitivo (unboxing) se necesitan usar los métodos de las clases envoltorio.

Todas estas operaciones complicaban excesivamente el código. Por ello a partir de J2SE 5.0 se introdujo una conversión automática (autoboxing) que permite asignar y obtener los tipos primitivos sin necesidad de utilizar las clases envoltorio.

Por ejemplo:

int enteroPrimitivo = 420;
Integer Entero = enteroPrimitivo;  //Se permite la asignación directa. Se llama autoboxing.
int otroEnteroPrimitivo = Entero;  //Se asigna directamente. Se llama autounboxing.

De modo que ahora el compilador según el caso se encarga de crear el objeto envoltorio o de extraer el tipo primitivo.

También se permite en el paso de parámetros y en expresiones aritméticas.

 
1 comentario

Publicado por en 11 octubre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , , , , , ,

Asignaciones – Arrays

Un array es un objeto que nos permite guardar varios elementos de un mismo tipo. Un array puede guardar valores de tipo primitivo o de tipo de referencia, pero el array siempre será un objeto y como tal se almacena en la memoria dinámica, el Heap.

Los arrays pueden ser unidimensionales (vectores) o multidimensionales (matrices).

En la imagen superior tenemos un ejemplo de un array unidimensional de longitud n. El índice de los arrays en Java siempre empiezan en 0, por tanto la última posición será n-1. El índice nos permite acceder a un elemento determinado del array.

En los arrays multidimensionales tendremos tantos índices como dimensiones.


Declaración de un array

Un array se declara especificando el tipo del array a la variable:

char[] arrayCaracteres;
char arrayVocales [];        //posición de los corchetes legal pero menos legible.
String[] arrayCadenas;
int[] cuponOnce;
int[][] matriz;

La declaración del array crea una referencia que apuntará al array.
La declaración nunca debe indicar el tamaño del array.


Creación de un array

arrayCaracteres = new char[20];
arrayVocales = new char[5];
arrayCadenas = new String[3];

Después de su creación los arrays se inicializan con el valor predeterminado de su tipo.

Aunque hemos separado la declaración de la construcción del array, lo más usual es que la declaración y la construcción se hagan en una misma línea:

int[] notasTrimestres = new int[4];

Java también permite utilizar una forma abreviada para crear arrays con valores iniciales dando los valores entre llaves:

char[] letras = {‘a’, ‘b’, ‘c’, ‘d’};
String[] nombres = {“María”, “Jose”, “Alberto”}


Arrays multidimensionales

Dado que es posible declarar un array de cualquier tipo, los arrays multidimensionales en Java se crean mediante arrays de arrays.

Un array bidimensional:
//Crea un array de tres elementos en los que cada uno de ellos es un array.  
int [][] bidimensional = new int [3][];

Ahora podemos dar a cada uno de estos tres arrays dimensiones diferentes si queremos:
bidimensional[0] = new int[2];
bidimensional[1] = new int[3];
bidimensional[2] = new int[2];

Si todos nuestros arrays de arrays van a tener la misma dimensión podemos ahorrarnos esfuerzo y  se permite la siguiente declaración y construcción:

int [][] rectangular = new int[3][2]



Límites

En Java todos los arrays comienzan en 0. El número de elementos de un array se guarda en el
atributo del array length. Es recomendable utilizar este atributo cuando iteremos los elementos de un array para evitarnos acceder fuera de los límites permitidos.

Si intentamos acceder a una posición incorrecta del array se generará la excepción ArrayIndexOutOfBoundsException.



Dando Valores a un Array

Podemos rellenar los arrays dando valor a cada uno de sus elementos:

 public class Persona {
     private String nombre;
     private int edad;
     //... // Constructores, getters, setters

    public static void main (String[] args){
        Persona[] familia = new Persona[3];
        familia[0] = new Persona("Maria", 35);
        familia[1] = new Persona("Jose", 30);
        familia[2] = new Persona("Ana", 3);
    }
 }
 

O bien utilizando un bucle:

public class Persona{
    private String nombre;
    private int edad;
    //...// Constructores, getters, setters

    public static void main (String[] args){
        String[] nombres = {"Maria", "Jose", "Ana"};
        int[] edades = {35, 30, 3};
        Persona[] familia = new Persona[3];

        for (int i = 0; i< familia.length; i++){
           familia[i] = new Persona(nombres[i], edades[i]);
        }
     }
 }
 



Asignaciones Legales en Arrays

De tipos primitivos:  
Se puede asignar a una posición del array cualquier variable que pueda ser promovidos o convertidos al tipo del array.

Por ejemplo, en un array de enteros podemos incluir shorts, bytes, chars …

public class asignaArray{
  public static void main(String[] args){
      byte a = 3;
      short b = 30000;
      int c = 450;
      long d = 300000L;
      float e = 2500.203F;
      double f = 3234.25;
      char g = 'B';
      int [] enteros = new int[10];
      enteros[0] = a;
      enteros[1] = b;
      enteros[2] = c;
      enteros[3] = (int) d;
      enteros[4] = (int) e;v
      enteros[5] = (int) f;
      enteros[6] = g;
      enteros[7] = c/a;
      enteros[8] = (int) d/a;
      enteros[9] = (int) e/a;</p>
      for (int i = 0; i< enteros.length; i ++){
          System.out.println("enteros["+ i + "]: " + enteros[i]);
      }
    }
 }
 

De tipos de referencia: Se puede asignar cualquier subclase del tipo. Y si el tipo del array es una interfaz podemos asignar cualquier objeto que implemente dicha interfaz.


Por ejemplo, podríamos tener un array de Empleado con distintos tipos de empleado:

//...
 Empleado[] empleados = new Empleado[4];
 empleados[0]=new Tecnico();
 empleados[1]=new Secretario();
 empleados[2]=new Contable();
 empleados[3]=new Tecnico();

for (int i=0; i<empleados.length; i++){
    Empleado e = empleados[i];
    System.out.println(e.getNombre());
    System.out.println(e.getAntiguedad());
    System.out.println(e.getSueldo());
 }
 //...

Es incluso posible hacer una colección con objetos de cualquier clase, ya que en Java todos los
objetos heredan de Object:

Object [] objetos = new Object[5];
objetos[0] = new Empleado();
objetos[1] = new Batman();
objetos[2] = new Libro();
objetos[3] = new String("Maria");
objetos[4] = new Bicicleta();
 
4 comentarios

Publicado por en 8 octubre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , , , ,

Asignaciones – Paso de Parámetros en Java

El paso de parámetros en Java se hace siempre por valor, ya se trate de un tipo primitivo o de un tipo de referencia, el método trabaja con una copia de la variable.

En el caso de una variable de tipo primitivo, si dentro del método se  modifica la variable, estamos modificando la copia y no la variable original.

En el caso de variables de referencia, si se modifica la variable dentro del método se está modificando una copia de la referencia y no la referencia original. Eso sí, al tener una copia de la referencia que apunta al mismo objeto, sí se puede cambiar el contenido de éste.

Veámoslo con un ejemplo:

class PasoParametros{

    public static void main(String[] args){

    //Para un entero comprobamos que se modifica la copia, despues vuelve a su valor orig.
        int entero = 100;
        System.out.println("Antes de modificar: " + entero);
        modificar(entero);
        System.out.println("Despues de modificar: " + entero);

    //Para un array de un entero, comprobamos que con la copia de la referencia
    //podemos cambiar su contenido.
        int[] array = new int[1];
        array[0] = 100;
        System.out.println("\nAntes de modificar: " + array[0]);
        modificarContenido(array);
        System.out.println("Despues de modificar: " + array[0]);

    //Para el mismo array de entero, comprobamos que no podemos modificar la referencia.
        System.out.println("\nAntes de modificar: " + array[0]);
        modificar(array);
        System.out.println("Despues de modificar: " + array[0]);

    }

    static void modificar(int e){
        e = 200;
        System.out.println("Dentro de modificar: " + e);
    }

    static void modificarContenido(int[] a){
        a[0] = 200;
        System.out.println("Dentro de modificarContenido: " + a[0]);
    }

    static void modificar (int[] a){
    //Creamos un nuevo array "b" y hacemos que "a" apunte a este nuevo array.
    //Funciona solo dentro del metodo, puesto que "a" aquí es una copia.
        int[] b = new int[1];
        b[0] = 300;
        a = b;
        System.out.println("Dentro de modificar: " + a[0]);
    }

}

Resultado de la ejecución:

 
Deja un comentario

Publicado por en 28 septiembre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , , ,

Asignaciones – Asignaciones, Widening, Cast

La operación de asignación nos sirve para dar valor a una variable.

La forma genérica de una asignación es la siguiente:
variable = valor;

Donde valor puede ser un literal, otra variable o una expresión.

El proceso de la asignación se realiza en dos fases. En primer lugar, se evalúa la parte derecha y se obtiene un valor. En segundo lugar, se asigna ese valor a la variable de la parte izquierda.

Literales

Ya comentamos que tenemos ocho tipos primitivos en Java: byte, short, int, long, float, double, char y boolean. Un literal es un valor concreto de un tipo.

Enteros
Se pueden representar utilizando una notación decimal, octal o hexadecimal.
15        formato decimal.
017      formato octal, el prefijo 0 indica un valor octal.
0xF     formato hexadecimal, el prefijo 0x indica un valor hexadecimal.

Un literal entero se considera por defecto de tipo int. Para indicar que queremos que sea de tipo long debemos acompañarlo de ‘l’ o ‘L’. Algunos literales enteros: 15, 320, 29999, 130000, 250L.

Reales
Un literal real se considera por defecto de tipo double. Para indicar que queremos que sea de tipo float debemos acompañarlo de ‘f’ o ‘F’. Algunos literales reales en coma flotante: 3.4, 1293.239, 150.23F.

Carácter
Un literal char se escribe entre comillas simples. Como son carácteres Unicode también se puede especificar el carácter en concreto por sus dígitos hexadecimales.
Algunos literales char: ‘b’, ‘z’, ‘\n’, ‘\t’, ‘\u003B’

Lógico
Los literales son false y true.


Expresiones

Es frecuente que nos encontremos expresiones en la que participan diferentes tipos de datos. Algunos tipos de datos pueden ser compatibles (enteros con caracteres p.e),  mientras que otros no (enteros con reales).

Los booleanos no son compatibles con ningún otro tipo de dato.

En las expresiones con datos enteros el resultado será al menos un int o el tipo del mayor operando de la expresión.

byte a = 10;
byte b = 20;
byte c  = (a + b) * 0.5; //El resultado de (a+b) * 0.5 es de tipo double.

En este caso el compilador generará un error, se necesita una conversión.
En Java las conversiones pueden ser implícitas o explícitas.

Conversión Implícita (Widening)

Se produce cuando los tipos son compatibles y Java realiza la conversión de forma automática.
Siempre es posible asignar un valor de un tipo más pequeño en una variable de un tipo mayor.

Grande = Pequeño; //OK

 long a = 100;  //100 al ser un literal entero, es de tipo int.

No hay problema en guardar este valor en una variable long. La conversión es automática.

Conversión Explícita (Cast)

Cuando los tipos son incompatibles o existe la posibilidad de perder información en una asignación, el compilador dará un error pidiendo que se confirme esa asignación con una conversión explícita.

Pequeño = Grande; //ERROR

int a = 100L; //ERROR 100L es un literal de tipo long y se quiere asignar a una variable int.
int a = (int) 100L; // OK

El compilador generará error. Como sabemos que en la asignación no hay peligro de perder información al
caber 100 perfectamente en un int, convertimos explícitamente.


Casos Posibles de Asignaciones

    • Asignación de Iguales: Se produce cuando el tipo del valor a asignar coincide con el tipo de la variable. En esta situación no hay ningún problema.
      char c = 'a';
      int entero = 100;
      int suma = entero + 25;
      double precio = 950.283;
      boolean indCerrado = false;
      

En estas asignaciones es necesario ningún tipo de conversión.

    • Conversión de ampliación (Widening): Ocurre cuando el tipo del valor a asignar es más pequeño que el tipo de la variable.
      //grande = pequeño;  //OK
      int a = 150;  //Declaramos un entero
      long var = a; //La variable a se puede asignar al long var, ya que vamos de pequeño a grande.
      double b = 15.3f * var;
      

Cualquier expresión entera siempre se podrá asignar a una variable double, ya que es el mayor tipo entero.

  • Conversión de reducción (Narrowing): Ocurre cuando el tipo del valor a asignar es más grande que el tipo de la variable. Es necesaria la conversión explícita.
    //pequeño = grande; //ERROR
    //pequeño = (pequeño) grande; //OK
    
    long grande = 5500L;
    int pequeño = (int) grande; //Es necesario hacer un casting a int.
    
    byte primero = 5;
    byte segundo = 20;
    byte suma = (byte) (primero + segundo); //La suma de dos bytes es un int, por lo tanto necesita
    //un casting a byte.
    
    • Excepción:
      Cuando el valor a asignar es una expresión onstante de tipo byte, short, char o int el
      compilador hace la conversión automáticamente. Esto se llama compile-time narrowing of constants:

      byte auto = 10; //OK, no hace falta hacer byte auto = (byte) 10;
      

      Si la variable a asignar es final y “cabe” en el destino no es necesario casting:

      final short prueba = 100;
      byte destino = prueba; //OK
      
      final short prueba = 300; //sobrepasa el valor posible para los byte.
      byte destino = prueba; //ERROR: possible loss of precision
      
    • Nota:
      Aunque tengamos un valor real que pueda caber en un “float” y lo queremos asignar a un
      double, siempre será necesario el sufijo o el casting:

      float f = 500.7; //ERROR
      float f = 500.7f; //OK
      float f = (float) 500.7; //OK
      
  • Conversión de Tipos de Referencia:Se puede asignar a un tipo menos especializado un tipo más especializado en la jerarquía.Padre = Hijo //OK
    Persona pe = new Programador();
    

    Esto es posible porque un objeto hijo (más especializado) puede hacer todo lo que haga el
    padre (menos especializado) pero no al revés.

    Hijo = Padre //ERROR

    Programador pro = new Persona(); //ERROR
    
 
6 comentarios

Publicado por en 27 septiembre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , ,

Asignaciones – Heap y Stack.

El Heap (Montículo) y el Stack (Pila) son diferentes memorias que utiliza la Java Virtual Machine de Java.

Mientras que para cada thread en la JVM se tiene un Stack privado, el Heap es un espacio de memoria dinámica único que se crea al inicio de la máquina virtual. El administrador del Heap es el sistema de administración de almacenamiento automático o más conocido como Garbage Collector.

¿Qué se guarda en el Stack?
– variables locales
– variables de referencia
– parámetros y valores de retorno
– resultados parciales
– el control de la invocación y retorno de métodos

¿Qué se guarda en el Heap?
– objetos
– variables de instancia

Ejemplo:

public class EjemploStackYHeap{
    int atributoEntero;
    String atributoCadena;

    public void setAtributoEntero (int x) {
        atributoEntero = x;
    }

    public void setAtributoCadena(String s) {
        atributoCadena = s;
    }

    public static void main (String[] args){
        int enteroLocal = 5;
        String cadenaLocal = "atributo";

        EjemploStackAndHeap e = new EjemploStackAndHeap();
        e.setAtributoEntero (enteroLocal);
        e.setAtributoCadena (cadenaLocal);
    }
}

Comienza la ejecución con main.
Se declara e inicializa una variable de tipo primitivo, enteroLocal.
Se almacena esta variable y su valor en el Stack.

Se declara e inicializa una variable de tipo de referencia.
La variable se crea en el Stack. El objeto se crea en el Heap.
La variable apunta al objeto String en el Heap.

Se llama al constructor EjemploStackAndHeap(). El constructor crea en el Heap el espacio para el objeto y sus atributos. Se inicializan los valores según el tipo de los atributos. En el Stack se crea la variable de referencia e que apunta al objeto en Heap.

Se llama a setAtributoEntero con el parámetro enteroLocal. La variable del método setAtributoEntero x recibe el valor de enteroLocal. Se le asigna el valor de x a atributoEntero. (El método tiene una variable this que apunta al objeto, de esta forma puede acceder a sus atributos).

Se llama a setAtributoCadena con el parámetro cadenaLocal. La variable del método setAtributoCadena s recibe el valor de cadenaLocal. Se le asigna el valor de s a atributoCadena. (El método tiene una variable this que apunta al objeto, de esta forma puede acceder a sus atributos).

Mas información:
http://tech-read.com/2008/12/15/jvm-stack-and-heap/

 
3 comentarios

Publicado por en 19 septiembre, 2011 en Estudio, Tema 3

 

Etiquetas: , , , , ,

 
A %d blogueros les gusta esto: