Resumen OCP(SCJP): Capítulo 3. Asignaciones

por | junio 28, 2013

LITERAL DE CARACTERES (OBJETIVO 1.3)

Recordemos, los caracteres son enteros de 16-bit sin signo. Esto significa que podemos asignar un número literal, asumiendo que podremos meterlo en un rango de 16-bit sin signo /65535 o menos). Por ejemplo, lo siguiente es legal:

char a = 0×892; // Literal hexadecimal
char b = 982; // Literal entero
char c = (char) 70000; // El cast requerido; 70000 fuera del rango char
char d = (char) -99; // Ridiculo, pero legal

Y lo siguiente son ejemplos no legales que producirán un error de compilador:

char e = -29; // Posible perdida de precisión; necesita un cast
char f = 70000; // Posible perdida de precisión; necesita un cast

Podemos también usar un caracter de escape si queremos representar un caracter que no se escribe como un literal,

char c = '\"';     // Doble comilla
char d = '\n';      // Nueva linea

ASIGNACIONES DE PRIMITIVOS (OBJETIVO 1.3)

Sabemos que un entero literal es siempre un int, pero mas importante, el resultado de una expresión que contenga cualquier cosa que sea int o mas pequeña siempre será un int. En otras palabras, si sumamos 2 byte entre ellos obtendremos un int. Multiplicando un int y un short nos dará un int. Dividir un short por un byte nos dará un int. Bien, ahora estamos en la parte extraña. Probemos esto:

byte a = 3; // No hay problema, 3 entra en un byte
byte b = 8; // No hay problema, el 8 entra en un byte
// No debería ser un problema, la suma de 2 bytes devuelve un int
byte c = a + b; //no compila,Type mismatch:cannot convert from int to byte
//esto si complia
byte c = (byte) (a + b);

CASTING DE PRIMITIVOS (OBJETIVO 1.3)

  • Poner una cosa pequeña (como un byte) en un contenedor mas grande (como un int).
  • No se puede poner una cosa grande (como un long) en un contenedor mas pequeño (como un short). El valor grande en un contenedor pequeño requiere una conversión mas estrecha y por tanto requeriría un cast explícito
int a = 100;
long b = a; //Cast implícito, un valor int siempre entra dentro de un long

//un valor entero puede entrar en un double de 64-bit.
double d = 100L; //Cast implícito

.

loat a = 100.001f;
int b = (int) a; //Cast explícito, el float podría perder información

// asignar un valor double a un tipo entero, conversión mas estrecha
int x = 3957.229;   // Ilegal

int x = (int) 3957.229; // Cast Legal

No obtenemos un error en tiempo de ejecución, incluso si el valor está siendo convertido es muy grande para el tipo de dato. Los bits en la izquierda por debajo del 8 se pierden. Si el bit mas a la izquierda (el bit de signo) en el byte (o cualquier integer primitivo) ahora parece ser un 1, el primitivo tendrá valor negativo.

long l = 130L;
//el byte solo puede guardar hasta 127
byte b = (byte)l; // el cast funciona, si compila
System.out.println("El byte es " + b);//pero el valor de salida es
//                    El byte es -126

El operador compuesto de asignación += nos permite agregar al valor de b, sin tener que poner un cast explícito. De hecho, +=, -=, *= y /= pondrán un cast implícito.

byte b = 3;
b += 7;

ÁMBITO DE VARIABLE (OBJETIVOS 1.3 Y 7.6)

class Layout{ // Clase

    static int s = 343; // Variable static

    int x;              // variable de Instancia

    {                   // Bloque de Inicialización
        x = 7;
        int x2 = 5; //variable inicio del bloque, como variable local
    }

    Layout(){         // Cosntructor
        x += 8;
        int x3 = 6;//variable constructor, como variable local.
    }

    void doStuff(){   // Método

        int y = 0;    // Variable Local

        for (int z = 0; z < 4; z++){
            y += z + x;
        }
    }

}

ASIGNACIONES BÁSICAS (OBJETIVOS 1.3 Y 7.6)

  • Los literales de números enteros son implícitamente del tipo int.
  • Los números de punto flotante son implícitamente del tipo double (64 bits).
  • La reducción de un tipo primitivo implica el truncamiento de los bits de orden más altos (bits de más a la izquierda).

VARIABLES DE INSTANCIA. VALORES POR DEFECTO DE LAS VARIABLES (OBJETIVOS 1.3 Y 7.6)

Tipo de Variable Valor por defecto
Referencia a Objeto null (no se refiere a ningún objeto)
byte, short, int, long 0
float, double 0.0
boolean false
char \u0000'

PASANDO VARIABLES HACIA MÉTODOS (OBJETIVO 7.3)

  • Los argumentos de un método nunca son objetos, si no referencias a estos.
  • Un argumento de tipo primitivo es una copia (desenlazada de la variable original) del valor de otra.

DECLARACIÓN DE ARREGLOS, CONSTRUCCIÓN E INICIALIZACIÓN (OBJETIVO 1.3)

//               0[0,1,2,3], 1[0,1], 2[0,1]
int[][] scores = {{5,2,4,7}, {9,2},  {3,4}};
//      sacar el     2        9       3
System.out.println(scores[0]);//[I@723704
System.out.println(scores[0][1]);//2
System.out.println(scores[1][0]);//9
System.out.println(scores[2][1]);//4

Un arreglo de tipo primitivo puede aceptar cualquier valor que pueda ser promovido implícitamente al tipo del arreglo. (Por ejemplo un valor de tipo byte puede almacenarse en un arreglo de tipo int)

int[] weightList = new int[5];
byte b = 4;
char c = 'c';
short s = 7;
weightList[0] = b;  // Ok, un byte es mas pequeño que un int
weightList[1] = c;  // Ok, un byte es mas pequeño que un int
weightList[2] = s;  // Ok, un byte es mas pequeño que un int

Se puede asignar un arreglo de un tipo, a una referencia ya declarada de un arreglo de un supertipo. (Por ejemplo, si Honda extiende de Car, un arreglo de objetos Honda puede ser asignado a un arreglo declarado de tipo Car).
Algo parecido con las interfaces

interface Sporty{
    void beSporty();
}

class Ferrari extends Car implements Sporty{

    public void beSporty() {
        // Implementa el método de Sporty en la clase Ferrari
    }

}

class RacingFlats extends AthleticShoe implements Sporty{

    public void beSporty() {
        // Implementa el método Sporty
    }

}

class GolfClub{ }
class TestSportyThings{
    public static void main(String[] args){
     Sporty[] sportyThings = new Sporty[3];
     sportyThings[0] = new Ferrari();//OK, Ferrari implementa Sporty
     sportyThings[1] = new RacingFlats();// Ok, Racing implementa Sporty
     sportyThings[2] = new GolfClub();// NO!, Golf no implementa Sporty
    }
}

BLOQUES DE INICIALIZACIÓN (OBJETIVO 1.3 Y 7.6)

Los bloques de inicialización de instancia se ejecutan cada vez que se crea un nuevo objeto. Se ejecutan luego de los constructores de las clases padres y antes del constructor de la clase actual.

class Init{
    Init (int x) {
        System.out.println("1-arg const");
    }

    Init(){
        System.out.println("no-arg const");
    }

    static {
        System.out.println("1st static init");
    }

    {
        System.out.println("1st instance init");
    }

    {
        System.out.println("2st instance init");
    }

    static{
        System.out.println("2nd static init");
    }

    public static void main (String[] args){
        new Init();
        new Init(7);
    }
}
1st static init
2nd static init
1st instance init
2st instance init
no-arg const
1st instance init
2st instance init
1-arg const

UTILIZANDO ENVOLTORIOS (WRAPPERS) (OBJETIVO 3.1)

Los constructores de las clases envoltorio pueden tomar como argumento un tipo String o un primitivo, salvo Character, el cual solo puede tomar el tipo primitivo char.

Primitivos Clase Contenedora Argumentos del Constructor
boolean Boolean boolean o String
byte Byte byte o String
char Character char
double Double double o String
float Float float, double o String
int Integer int o String
long Long long o String
shortShort short o String

BOXING (OBJETIVO 3.1)

  • “Widening conversion” es el mecanismo de almacenar un dato pequeño en un contenedor más grande.
  • El compilador escogerá la opción de widening antes que el boxing.
  • El compilador elegirá el estilo antiguo antes de elegir el estilo nuevo.
  • El método var-args es mas “flojo” que el otro método
  • Para métodos sobrecargados utilizar el mecanismo widening sobre primitivos se traduce en invocar el método con argumento “más chico”.
  • Utilizados individualmente, tanto el mecanismo boxing como el var-arg son compatibles con la sobrecarga.
    No se puede utilizar el mecanismo widening de un tipo wrapper a otro (estos son objetos y no se cumple con la relación ES-UN).
  • No se puede utilizar el mecanismo widening y luego el boxing. (Un valor de tipo int no se puede convertir en un Long).
    Se puede utilizar el mecanismo boxing y luego el widening. (Un valor de tipo int se puede convertir en un Object, a través del tipo Integer).

SOBRECARGANDO

Para métodos sobrecargados utilizar el mecanismo widening sobre primitivos se traduce en invocar el método con argumento “más chico” de los posibles que pueden ser invocados.

public static void main(String[] args) {
		byte b = 5;
		short s = 5;
		long l = 5;
		float f = 5.0f;
		go(b);
		go(s);
		go(l);
		go(f);
	}

static void go(int x) {System.out.println("int");}
static void go(long x) {System.out.println("long");}
static void go(double x) {System.out.println("double");}
int
int
long
double

No se puede utilizar el mecanismo widening de un tipo wrapper a otro (estos son objetos y no se cumple con la relación IS-A).

public static void main(String[] args) {
   Integer i;
   doX(i); //no compila
}

static void doX(Long x) {}

Se puede utilizar el mecanismo boxing y luego el widening. (Un valor de tipo int se puede convertir en un Object, a través del tipo Integer).

public static void main(String[] args) {
   byte b = 5;
   go(b);
   //b -> Byte(Box) y luego Byte -> Object(widening)
}

static void go(Object o){
   Byte b =(Byte)o;
   System.out.println(b);
}

Se puede combinar el mecanismo var-arg tanto con widening como con boxing

public static void main(String[] args) {
		int i = 5;
		//wideing -> vargs
		//int i cabe en un long(wideing)
		wide_vargs(i);

		//boxing -> vargs
		//int -> Integer(boxing)
		box_vargs(i);
	}

	static void wide_vargs(long...x) {
		System.out.println("long...");
	}

	static void box_vargs(Integer...x) {
		System.out.println("Integer...");
	}

Las 5 reglas de oro

http://www.coderanch.com/t/417622/java-programmer-SCJP/certification/Golden-Rules-widening-boxing-varargs

Rules :

  1. Primitive Widening -> Boxing -> Varargs.
  2. Widening and Boxing (WB) not allowed.
  3. Boxing and Widening (BW) allowed.
  4. While overloading, Widening + vararg and Boxing + vararg can only be used in a mutually exclusive manner i.e. not together.
  5. Widening between wrapper classes not allowed

Now Let me illustrate each of them with instances :

Metodos Sobrecargados Código de llamada Método llamado
doX(Integer i) & doX(long l) doX(5) long (by Rule 1)
doX(int…i) & doX(Integer i) doX(5) Integer (by Rule 1)
doX(Long l) & doX(int…i) doX(5) int…i (Rule 2 & 1)
doX(Long l) & doX(Integer…i) doX(5) Integer…i(R. 2&1)
doX(Object o) & doX(Long l) doX(5) Object o (Rule 2&3)
doX(Object o) & doX(int…i) doX(5) Object o (Rule 3&1)
doX(Object o) & doX(long l) doX(5) long l (Rule 3&1)
doX(long…l) & doX(Integer…i) doX(5) ambiguous (Rule 4)
doX(long…l) & doX(Integer i) doX(5) Integer (Rule 1)
doX(Long l) Integer i;
doX(i)
error (Rule 5)
doX(Long l) & doX(long…l) Integer i;
doX(i)
long…l(Rule 5 & 1)

EOF