Material de apoio para a vídeo-aula nº 7 do Curso de Java ministrado no Ponto G++, contendo toda a base teórica para um sólido acompanhamento da aula.

Java Curiosa & Divertida

Um exemplo concreto das coisas estranhas que acontecem quando o limite dos tipos inteiros que usam o sistema de complemento de dois é estourado, ocorreu recentemente quando o contador de visualizações do YouTube ultrapassou seu limite de 32 bits no vídeo do clip musical Gangnam Style que, como se diz, "viralizou" de uma forma inimaginável.

O pessoal da Google pensou que certamente um vídeo jamais ultrapassaria a barreira das 2 bilhões e pouco visualizações, e adotou um tipo inteiro de 4 bytes para representar o contador, cujo limite exato é 2.147.483.647.

Mas isso acabou acontecendo no final de 2014, e a notícia foi amplamente divulgada pela midia, conforme pode ser visto abaixo.

gangnam overflow

Na verdade, houve um certo exagero sensacionalista nessas notícias. Os engenheiros da Google já haviam observado que "Gangnam Style" havia atingido 2 bilhões de visualizações em maio daquele ano e, embora a fase viral já tivesse passado, com certeza ocorreria um overflow em breve e, assim, tiveram tempo mais que suficiente para a correção do problema, por sinal bastante simples, bastando modificar a alocação de memória naquele ponto de 32 para 64 bits. Nunca houve, de fato, um estouro no código do YouTube.

Colocaram até um ovo de páscoa no contador, de forma que, ao passar com o cursor sobre o mesmo, ele simulava um odômetro, mudando para o número negativo, representando o tal "estouro".

Aproveitamos este incidente para fixar nesta seção os conceitos de tipos primitivos, seus limites e, principalmente, o funcionamento do complemento de dois. O programa abaixo demonstra isso de uma forma bem simples:

package br.com.pontogpp;

public class YoutubeCounter {

    public static void main(String[] args) {

        // limite positivo do int de 32 bits é 2.147.483.647
        int contadorVelho = 2147483647;
        System.out.println(contadorVelho);

        // se o limite positivo for estourado, a variável assume o limite
        // inferior negativo
        ++contadorVelho;
        System.out.println(contadorVelho);

        // o limite do tipo long (64 bits) é bem maior: 9.223.372.036.854.775.807
        long contadorNovo = 2147483647;
        ++contadorNovo;
        System.out.println(contadorNovo);

    }

}

Tipos Primitivos

O tipo char

Embora ainda dentro do grupo dos inteiros, o char difere dos demais tipos por ser o único unsigned, isto é, sem sinal e, portanto, não usa sistema de complemento de dois. O motivo disso é porque este tipo é usado para representar os caracteres da codificação Unicode UTF-16, que é o padrão em Java.

O programa abaixo serve para demonstrar as peculiaridades do tipo char:

public class CharsTour {

    public static void main(String[] args) {

        char x = 'a', y = 'b';
        System.out.println(x);
        System.out.println(y);
        System.out.println(x + y);
        System.out.println(); // insere uma linha vazia entre este e o bloco seguinte

        x = 97;
        y = 98;
        char z = ' ';
//      x = x + y; // Erro de compilação: "Type mismatch: cannot convert from int to char"
        z = (char)(x + y); // cast explícito, retorna char; OK
        System.out.println(z);
        x += y; // Operação e atribuição composto; OK também
        System.out.println(x);
        System.out.println();

        System.out.println(((Object)('a' + 'b')).getClass());
        System.out.println();
        // saída: class java.lang.Integer

        // concatenando os caracteres como String:
        System.out.println('a' + "" + 'b');
        System.out.println("" + 'a' + 'b');
        System.out.println('a' + 'b' + ""); // "195"
        System.out.println();

        System.out.println(new String(new char[] { 'a', 'b' }));
        System.out.println(new StringBuilder().append('a').append('b').toString());
        System.out.println(String.format("%c%c", 'a', 'b'));

    }

}

O programa é composto por cinco blocos, que passamos a examinar mais detalhadamente.

No primeiro bloco, fazemos a atribuição dos caracteres 'a' e 'b' às variáves x e y (linha 5). Vejam que os literais dos caracteres são identificados por aspas simples. Observem, também, como podemos fazer as atribuições numa única linha de código, usando a vírgula para separar as variáveis.

Nas linhas seguintes, usamos o método System.out.println() para exibir os valores de x, de y e o resultado da expressão x + y. A última saída é a única que apresenta surpresa, pois seu valor é o inteiro 195, correspondente à soma de 97 e 98, que são os códigos Unicode dos caracteres 'a' e 'b', como pode ser conferido nesta tabela.

Isso ocorre porque, internamente, o tipo char é tratado como um inteiro, como vimos no início deste estudo. Isso pode ser confirmado com o código apresentado no terceiro bloco do programa (linhas 21 a 23). É feito, então, um "casting" silencioso pelo compilador do resultado da expressão, que é passado como Integer para o método System.out.println().

No segundo bloco, temos mais algumas operações com o char, para deixar a coisa mais clara. Se você remover o comentário da linha 14, o IDE deverá exibir um erro de incompatibilidade de tipos (Type mismatch) e o programa não poderá ser compilado. Isso, pela mesma razão que vimos acima, ou seja, o casting silencioso para integer, feito pelo compilador.

Na linha 15, demonstramos como fazer o casting explícito para transformar o resultado da expressão no seu char equivalente e, na linha 17, mostramos que é possível o uso de operadores compostos.

No quarto bloco, são demonstradas formas simples de concatenação de caracteres para formação de uma String. Atente que na linha 28, o resultado apresentado é a String "195" e não o Integer 195.

Finalmente, no último bloco do programa (linhas 31 a 33), são mostrados outros métodos para concatenação de caracteres em string. Seu uso ficará mais claro, quando avançarmos no estudo da orientação a objeto.


comments powered by Disqus