Atribuindo valores à variáveis – Widening, Narrowing e Boxing

 
 

Tipos nativos numéricos:


 

 
 

No estudo abaixo, veremos como funciona a atribuição de valor para uma variável (tanto de tipo nativo quanto de tipo de referência). Também veremos o que é uma constante em tempo de compilação e o que um literais tem a ver com isso. Ao final veremos operações com variáveis.

 
 

 
 

Atribuição de valores em variáveis:

 
 

public class Numero {

public static void main(String[] args){

// tipos nativos

byte b = 7; // compila (narrow int to byte)

char c = 7; // compila (narrow int to char)

short s = 7; // compila (narrow int to short)

int i = 7; // compila

long l = 7; // compila (um int cabe dentro de um long. Lembre-se da quantidade de bytes. Tipos nativos numéricos )

float f = 15; // compila (um int cabe dentro de um float. Idem acima)

double d = 15; // compila (um int cabe dentro de um double. Idem acima)

//float f2 = 15.0
// não compila (O literal ‘15.0’ por padrão é um double)

 
 

 
 

 
 

// Boxing classes

Character c1 = 7; // compila (narrow int to char then box to Character)

Byte b1 = 7; // compila (narrow 7 para byte then box para Byte)

Short s1 = 7; // compila (narrow then box)

Integer i1 = 7; // compila (box)

//Long l1 = 7;
// não compila (primeiro box 7 (int) to (Integer) só que Integer não tem relação com Long. Integer extende Number assim como Long também.)

 
 

// Box then widen

Number n = 7L; // compila (box to Long then widen to Number)

Number n1 = 7; // compila (box to Integer then widen to Number)

Number n2 = 7.0F; // compila (box to Float then widen to Number)

Number n3 = 7.0D; // compila (box to Double then widen to Number)

 
 

// Narrowing não funciona para tipos decimais:

//float f = 46.45;
// não compila (o número é um double por padrão.

 
 

 
 

double d3 = 46.45; // compila (double é o tipo padrão para literais decimais)

double d4 = 46.45F; // compila (um float cabe dentro de um double. Lembre-se da qtd de bytes. Tipos nativos numéricos)

//Double d3 = 46.45F;
// não compila (Boxing 46.45F to Float than … crash !!!)

Double d5 = 46.45; // compila (apenas boxing)

 
 

// passar parâmetros para métodos não é o mesmo que atribuir variáveis

//doByte(7); // não compila (não ocorre o narrowing do int ‘7’ para byte como em: byte b = 7;)

doLong(7); // compila (o int ‘7’ cabe dentro de um long)

 
 

// Ambas não compilam, pois Integer não tem relação direta nem com Byte nem com Long.

//doObjectLong(7); // não compila

//doObjectByte(7); // não compila

 
 

 
 

}

public static void doByte(byte b){}

public static void doLong(long l){}

 
 

public static void doObjectByte(Byte b){}

public static void doObjectLong(Long l){}

}

 
 

Pode se observar:

  • O literal 7 está na faixa de valor considerável para ser um byte, char, short e integer. No caso de byte, char e short o compilador entende que 7 (que é um literal int) pode ser ‘narrowed’ implicitamente.
  • Para o tipo ‘long’ o literal 7 (que é um int) cabe perfeitamente dentro dele. Veja acima:
    Tipos nativos numéricos
  • Para o tipo Long o literal 7 (que é um int) passa por duas etapas:

    1º) primeiro é realizado o boxing de int para Integer

    2º) depois é ‘tentado’ realizar o widening de Integer para Long. Como Integer e Long extendem Number porém não tem nenhuma relação direta, o widening entre eles é falho.

  • Para o método estático ‘doByte()’ o que ocorre é que ele espera receber um tipo ‘byte’ e recebe um tipo ‘int’ por isso não compila. Preste atenção que passar valores para parâmetros de métodos não é o mesmo que atribuir valores para variáveis (para efeito de compilador).
  • Para o método estático ‘doLong’ a compilação ocorre normalmente pois um ‘int’ cabe dentro de um ‘long’ (veja:
    Tipos nativos numéricos).
  • Para ‘doObjectLong’ e ‘doObjectByte’ temos como parâmetro respectivamente um tipo ‘Long’ e ‘Byte’. Ao passar o literal ‘7’ (que é um literal int) o compilador realiza o autobox para Integer que por sua vez não tem relação direta (de herança) com o tipo Byte e Long. Portanto ocorre um erro de compilação.

 
 

Regras de atribuição de variáveis:

Narrow then Box – OK

*apenas para (byte, short e int)

‘int i = 7L’ não compila. Muito menos ‘Integer i = 7L’

*para tipos decimais não funciona

‘float f = 46.45’ não compila. Muito menos ‘Float f = 46.45’

Box then Widening – OK

 
 

 
 

Veja também:

http://www.coderanch.com/t/463963/java-programmer-SCJP/certification/Wrapper-Assignments-ExamLab#2072541

 
 

http://www.coderanch.com/t/491879/java-programmer-SCJP/certification/conversion-autoboxing#2213470

 
 

Java Language Specification
explains that you can narrow int to byte, short or char if the int value is constant and in valid range of the target type: 

 
 

[…]A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable. 

 
 

A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is : 

Byte and the value of the constant expression is representable in the type byte. (ex: Byte b1 = 7;)

Short and the value of the constant expression is representable in the type short. (ex: Short s1 = 7;)

Character and the value of the constant expression is representable in the type char. (ex: Character c1 = 7;)[…]

 
 

Colado de <http://www.coderanch.com/t/491879/java-programmer-SCJP/certification/conversion-autoboxing#2213470>

 
 

O parágrafo acima quer dizer que quando um literal inteiro puder ser representado na faixa de um byte, char ou short, ele poderá ser convertido (narrowed) implicitamente.

 
 

http://www.coderanch.com/t/507079/java-programmer-SCJP/certification/wrappers-initialization-logic#2290117

 
 

You can box then widen. You cannot widen then box. 

 
 

Integer i = 15; 

This is fine: 15 is an int, and can be auto-boxed into an Integer. 

 
 

Number n = 15; 

Object ob = 15; 

These are fine. 15 is boxed to an Integer, which can then be widened to Number or Object as Integer is a sub-class of those. 

 
 

Long l = 15; 

15 is boxed to an Integer…which then can’t be converted to a Long. To work, the int would have to be widened to a long, and then boxed. But the compiler won’t do that for you.

 
 

Colado de <http://www.coderanch.com/t/507079/java-programmer-SCJP/certification/wrappers-initialization-logic#2290117>

 
 

veja também:

Overloading When Combining Widening and Boxing

You can box and then widen

 
 

 
 

Constante em tempo de compilação:

 
 

public class Numero {

public static void main(String[] args){

int i = 7;

byte b = i;

}

}

public class Numero {

public static void main(String[] args){

final int i = 7;

byte b = i;

}

}

public class Numero {

public static void main(String[] args){

final int i;

i = 7;

byte b = i;

}

}

Javac:

Numero.java:4: possible loss of precision

byte b = i;

^

required: byte

found: int

1 error

  

Javac:

ok

Javac:

Numero.java:5: possible loss of precision

byte b = i;

^

required: byte

found: int

1 error

 
 

 
 

O que muda do primeiro para o segundo código é que a variável i (no segundo caso) é declarada como ‘final’ e é atribuida um valor. Portanto, para o compilador ela é um constante em tempo de compilação.

 
 

Observação importante: Literais são equivalentes a Constantes em tempo de compilação. Veja logo abaixo em: Operações com variáveis:

 
 

 
 

Veja:

Arup when you define a field as final and assign it a value with the declaration, then it becomes a compile time constant. They get special treatment by the compiler. They can be used in case labels, assigned to a smaller datatype if in range etc. This is because they actually act like literals. When the compiler compiles the class, it replaces the name of the final field with the actual value of the final field.

 
 

Colado de <http://www.coderanch.com/t/442053/java-programmer-SCJP/certification/Assignment#1966601>

 
 

 
 

 
 

 
 

Operações com variáveis:

 
 

Veja também: Primitive Assignments

 
 

No exemplo abaixo, vamos diferenciar operações com variáveis e com literais.

 
 

public class Teste {

public static void main(String[] args) {

// O resultado de uma expressão com numeros inteiros (byte, short, int) é sempre um número inteiro

byte b1 = 7;

byte b2 = 12;

byte b3 = b1 – b2;
// não compila pois tem que ser explicitamente convertido

byte b4 = b2 + b2;
// não compila pois tem que ser explicitamente convertido

// o que ocorre acima é que ambas as operações podem “estourar” a capacidade da variável declarada “byte b3 e byte b4”

byte b3 = (byte) (b1 – b2);

// Para o compilador a soma de dois literais é diferente do que a soma de duas variáveis.

// No caso abaixo o resultado que é um int é ‘narrowed’ para byte para poder caber na variável b. (os literais 7 e 12 são constantes em tempo de compilação)

byte b = 7 + 12;

 
 

// idem para o caso dos bytes acima.

short s1 = 10, s2 = 20, s3 = s1 + s2;
// não compila pois tem que ser explicitamente convertido

short s1 = 10, s2 = 20, s3 = (short) (s1 + s2); // compila (foi realizada a devida conversão)

final short s1 = 10, s2 = 20, s3 = s1 + s2; // compila (os argumentos s1 e s2 foram declarados como ‘final’ e, portanto são considerados como Literais ou constantes em tempo de compilação para o compilador.)

short s = 10 + 12; // compila (a soma dos literais int podem ser convertidos para short)

short s = 10 + 12L;
// não compila (a soma dos literais gera um long que não poderá ser convertido para short)

 
 

// O resultado de uma expressão onde um operador seja do tipo long sempre será long

int i = 1000L + 200; // não compila pois o resultado da soma dos literais é do tipo long.

 
 

// Um resultado inteiro sempre caberá dentro de um long

int i1 = 1000;

int i2 = 2000;

long l5 = i1 + i2;

// ou

long l6 = 1000 + 2000;

 
 

//Neste caso não compila pois 7 + 7 gera um resultado inteiro que não pode ser autoboxed para Long.

Long l7 = 7+7;

int i = l2 + b1; // não compila pois o resultado também é um long        

Long l = (long)(i2 + i1);        

 
 

//No caso abaixo já compila pois como um operador é do tipo long o resultado será um tipo long que

//poderá ser autoboxed para Long.

Long l = 7L + 7;

 
 

 
 

float f = 1.75F + 7.25D;
// não compila pois o resultado é um double

 
 

Short sh = 7+7; // compila (narrow o resultado int ’14’ para short than box short para Short)

short sh = 7+7; // compila (narrow o resultado int ’14’ para short)

Short sh = 64000 + 1000;
// não compila pois o resultado que é um ‘int’ estoura a capacidade de ser um short

}

}

 
 

 
 

Esta entrada foi publicada em Java com as etiquetas . ligação permanente.

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s