class A { public static void main(String[] args){ Integer a1 = 125; Integer b1 = 125; System.out.println(a1==b1); //true } } class B { public static void main(String[] args){ Integer a2 = 280; Integer b2 = 280; System.out.println(a2==b2);//false } } class C { public static void main(String[] args){ Integer a3 = 280; System.out.println(a3==280);//true } }
Quem já estudou para certificação está acostumado com esse tipo de pegadinha. Para entender esse comportamento vamos analisar o bytecode da classe A e B:
class A extends java.lang.Object{
A();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 125
2: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: astore_1
6: bipush 125
8: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
11: astore_2
12: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
15: aload_1
16: aload_2
17: if_acmpne 24
20: iconst_1
21: goto 25
24: iconst_0
25: invokevirtual #4; //Method java/io/PrintStream.println:(Z)V
28: return
}
Podemos perceber o autoboxing acontecendo com o Integer.valueOf para as duas variaveis "a" e "b".
Se olharmos o código do método valueOf veremos que se os primitivos estiverem dentro de uma faixa (low e high) o objeto será buscado de um cache. Por padrão os valores do low e high são -127 e 128 respectivamente e podemos alterar o valor do high usando o parametro -Djava.lang.Integer.IntegerCache.high.
public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
Se o número estiver dentro da faixa, o objeto será sempre o mesmo, logo, a comparação com "==" será sempre true. Agora se o número estiver fora dessa faixa, o metodo valueOf sempre cria um novo objeto e a comparação com "==" será false.
Então por que no exemplo da classe C o resultado é true?
Neste caso, a comparação não é entre dois objetos e sim entre um objeto e um primitivo, isso só é possível por conta do unboxing. Vamos ver o bytecode:
class C extends java.lang.Object{
C();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: sipush 280
3: invokestatic #2; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
6: astore_1
7: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
10: aload_1
11: invokevirtual #4; //Method java/lang/Integer.intValue:()I
14: sipush 280
17: if_icmpne 24
20: iconst_1
21: goto 25
24: iconst_0
25: invokevirtual #5; //Method java/io/PrintStream.println:(Z)V
28: return
}
Vemos o unboxing acontecendo no método intValue(), então nesse caso a comparação passa a ser entre dois primitivos, o que explica o resultado true.
Para não cair nesse tipo de situação, o correto seria fazer a comparação utilizando o método equals.
Para não cair nesse tipo de situação, o correto seria fazer a comparação utilizando o método equals.
Nenhum comentário:
Postar um comentário