Métodos de Conversão de Classes Wrapper

xxxValue()

Quando é necessário converter o valor de um objeto wrapper para um primitivo, utiliza-se um dos métodos xxxValue(), onde xxx é o nome do primitivo para o qual será feita a conversão. Todos os métodos dessa família não possuem argumentos.
Cada uma das seis classes wrapper numéricas possuem seis métodos, de modo que qualquer objeto numérico wrapper pode ser convertido para qualquer tipo numérico primitivo. As classes wrapper não numéricas possuem apenas um método  xxxValue().

public class TestxxxValue { 
      public static void main(String[] args) {
            Integer i2 = new Integer(42);
            //converte o Integer para o primitivo byte
            byte b = i2.byteValue();
            //convert o Integer para o primitivo short
            short s = i2.shortValue();
            //converte o Integer p/ o primitivo double
            double d = i2.doubleValue();
           
            Float f2 = new Float(3.14f);
            //converte o Float para o primitivo short
            short s2 = f2.shortValue();
            /* imprime 3 porque no momento da
             * conversão a literal perde as casas
             * decimais, já que o short é inteiro */
            System.out.println(s2);
      }
}


parseXxx() e valueOf()

Os seis métodos parseXxx() , um para cada classe wrapper numérica, são parecidos com o valueOf(), que existe em todas as classes wrapper numéricas.
Os dois possuem uma String como argumento, lançam a exceção NumberFormatException se o argumento não tiver o formato apropriado, e podem converter objetos String de diferentes bases, quando o tipo primitivo em questão for qualquer um dos quatro tipos inteiros. A diferença entre os dois métodos é que o parseXxx() retorna um primitivo e o valueOf() retorna um novo objeto wrapped do tipo invocado pelo método.

public class TestparseXxx_valueOf {
      public static void main(String[] args) {
            //parseXxx converte de String p/ primitivo
            double d4 = Double.parseDouble("3.14");
           
            //valueOf converte se String p/ objeto
            Double d5 = Double.valueOf("3.14");

            //converte uma String (base2) p/ primitivo
            long L2 = Long.parseLong("101010", 2);
           
            //converte uma String (base2) p/ objeto
            Long L3 = Long.valueOf("101010", 2);
      }
}


toString()

A classe Object possui o método toString(). Como todas as classes herdam de Object, então todas as classes possuem esse método. A idéia desse método é permitir que se obtenha uma representação significativa de um dado objeto.
Consequentemente, todas as classes wrapper possuem uma instância sem argumento e não-estática desse método. Esse método retorna uma String com o valor primitivo do objeto.
Além disso, todas as classes wrapper fornecem um método toString() sobrecarregado e estático que recebe um tipo primitivo numérico apropriado e retorna uma String.
Interger e Long fornecem um terceiro método toString(), que é estático, seu primeiro argumento é um primitivo, o segundo argumento é a base e retorna uma String; por default o primeiro argumento está na base 10.

public class Test_toString {
      public static void main(String[] args) {
            Double db = new Double("2.55");
            // imprime 2.55
            System.out.println(db.toString());
           
            String valor = Double.toString(2.55);
            //imprime 2.55
            System.out.println(valor);
           
            //base 16
            String valor2 = Long.toString(156, 16);
            //imprime 9c
            System.out.println(valor2);
      }
}


toXxxString() - Binário, Hexadecimal e Octal

O Integer e Long permite converter números da base 10 para outras bases. Esses métodos de conversão recebem um int ou long, e retornam uma String do número convertido.

public class Test_toXxxString {   
      public static void main(String[] args) {
            //converte 166 para a base 16
            String s = Integer.toHexString(166);
            //imprime a6
            System.out.println(s);
           
            //converte 166 para a base 8
            String s2 = Long.toOctalString(166);
            //imprime 246
            System.out.print(s2);
      }
}


Fonte: SCJP Sun Certified Programmer for Java 6 Study Guide

Classes Wrapper

As classes wrapper em Java têm dois propósitos: prover o mecanismo de envolver valores primitivos em um objeto para que estes possam realizar atividades exclusivas de objetos (como ser adicionados em coleções ou ser retornado de um método que tenha um objeto como valor de retorno); e fornecer uma variedade de funções para os primitivos, como conversões para String ou para diferentes bases (binária, octal e hexadecimal).
Existe uma classe wrapper para cada tipo primitivo. Uma vez declarado o valor de um objeto wrapper, este nunca mais poderá ser mudado. Por exemplo, para o int existe a classe Integer, para o char existe a classe Character, para o long existe a classe Long, etc.

Construtores Wrapper

Todas as classes wraper, exceto Character, fornecem dois construtores: um com um argumento do tipo primitivo, e outro com um argumento do tipo String.
A classe Character fornece apenas um construtor, que leva um char como argumento.
Os construtores da classe Boolean podem receber os valoes true e false ou uma String correspondente a esses valores. Se a String é true (case-insensitive) o retorno será true, se for qualquer outro valor o retorno será false.
Quando as classes wrapper levam uma String como argumento e o valor não corresponde a uma literal válida, ou seja,  não pode ser convertido para o primitivo apropriado, é lançada a exceção NumberFormarException.
Somente a partir do Java 5.0 é possível tratar objetos wrapper como primitivos em expressões condicionais (if, por exemplo), porque o compilador irá automaticamente converter (unbox) o Boolean para um boolean.


public class ClassesWrapper {
      public static void main(String[] args) {
            Integer integer = new Integer(1);
            Integer integer2 = new Integer("1");
            Float flo = new Float(3.5);
            Float flo2 = new Float("3.5");
            Character character = new Character('c');
           
            Boolean bool = new Boolean(true);
            //também retorna retorna true
            Boolean bool2 = new Boolean("true");
           
            Boolean bool3 = new Boolean("false");
            //também retorna retorna false
            Boolean bool4 = new Boolean("teste");
           
            /* a partir do Java 5.0 é possível tratar
             * objetos wrapper como primitivos em
             * expressões condicionais */
            if (bool)
                  System.out.println("teste");
           
            /* quando a String não corresponde a
             * uma literal válida para a classe
             * wrapper a exceção NumberFormarException
             * é lançada */
            Byte bt = new Byte("3.5");
      }    
}


Métodos valueOf()

Os dois métodos static valueOf, fornecidos pela maioria das classes wrapper, trazem uma nova abordagem na criação de objetos wrapper.
Os dois métodos têm uma representação String do tipo primitivo como primeiro argumento, e o segundo método tem um argumento adicional int que indica em qual base (binária, octal ou hexadecimal) o primeiro argumento está representado.


public class TestValueOf {
      public static void main(String[] args) {
            /* o método valueOf possui duas
             * sobrecargas, uma com um argumento
             * String, e outra com dois argumentos:
             * um String e um int (corresponde a base
             * em que se encontra o número) */
            Float f2 = Float.valueOf("3.14f");
            //converte da base dois para a base 10
            Integer i2 = Integer.valueOf("101011", 2);          
      }    
}


Fonte: SCJP Sun Certified Programmer for Java 6 Study Guide

Blocos de Inicialização

Blocos de inicialização são executados quando a classe é carregada pela JVM, quando se trata de um bloco de inicialização estático, ou quando uma instância é criada, quando se trata de um bloco de inicialização de instância.
Blocos de inicialização não possuem nome e parâmetros, e não retornam nada.
O bloco de inicialização estático só roda uma vez, quando a classe é carregada pela primeira vez. Um bloco de inicialização de instância roda toda vez que uma nova instância da classe é criada.


public class BlocosInicializacao {
      static int var;
      int valor;
     
      //bloco de inicialização estático
      static {
            var = 2;
            /* variáveis de instância não podem
             * ser acessadas dentro de blocos
             * estáticos */
            valor = 4;
      }
     
      //bloco de inicialização de instância
      {
            var = 5;
            valor = 10;
      }    
}


O bloco de inicialização roda logo depois da chamada do método super() em um construtor; em outras palavras, depois que todos os métodos super() das superclasses forem chamados, porém antes do código do construtor.
É permitido ter vários blocos de inicialização em uma classe. Ao contrário de métodos e construtores, a ordem que os blocos de inicialização de instância aparecem em uma classe importa, ou seja, quando na hora de executar os blocos de instância, se a classe tiver mais de um, eles serão executados na ordem em que aparecem na classe, de cima para baixo.
Regras: blocos de inicialização de instancia são executados na ordem em que aparecem; blocos de inicialização estáticos só rodam uma vez, quando a classe é carregada pela primeira vez na JVM; blocos de inicialização de instância rodam toda vez que uma nova instância é criada; e blocos de inicialização de instância rodam depois da chamada do método super() dentro do construtor.
Se houver várias classes na árvore de herança com vários blocos estáticos, todos eles serão executados antes dos blocos de instância.


public class Java {
      //construtores
      Java(int x) {
            System.out.println("Construtor c/ arg");
      }
      Java() {
            System.out.println("Construtor s/ arg");
      }

      //blocos de inicialização
      static {
            System.out.println("Bloco estático 1");
      }
      {
            System.out.println("Bloco de inst. 1");
      }
      {
            System.out.println("Bloco de inst. 2");
      }
      static {
            System.out.println("Bloco estático 2");
      }

      public static void main(String[] args) {
            /* Ordem de execução: blocos estáticos 1 e
             * 2; ao chamar o construtor Java() serão
             * executados os blocos de instância 1 e
             * 2; logo depois o código do construtor 
             * será executado; ao chamar o construtor
             * Java(int x) os blocos de instância
             * serão executados novamente; logo depois
             * o código do construtor com argumento 
             * será executado*/
            new Java();
            new Java(7);
      }
}


Fonte: SCJP Sun Certified Programmer for Java 6 Study Guide

Inicializando Arrays

Inicializar um array significa colocar valores dentro dele. Esses valores são primitivos quando se trata de um array de primitivos, e referências a objetos (endereços de memória) quando se trata de um array de objetos. Nesse último caso o elemento pode estar também guardando o valor null.
Os elementos individuais no array são acessados através de número de índice. O número de índice sempre começa em zero. Isso significa que um array de 10 elementos começa no índice zero e termina no índice nove. Caso tente acessar um índice que não existe, a exceção ArrayIndexOutOfBoundsException será lançada.

import java.util.Date;

public class InicializacaoArrays {
      public static void main(String[] args) {
            /* array de primitivos com 2 elementos
             * os elementos inicial com seus
             * valores default - 0 */
            int[] codigos = new int[2];
            System.out.println(codigos[0]);//0
            System.out.println(codigos[1]);//0
           
            /* array de objetos com 2 elementos
             * inicializados com seus
             * valores default - null */
            Date[] datas = new Date[2];
            System.out.println(datas[0]);//null
            System.out.println(datas[1]);//null
            //ArrayIndexOutOfBoundsException
            System.out.println(datas[2]);
           
            //array de duas dimensões
            int[][] valores = new int[2][];
            /* a primeira posição do array foi
             * inicializada com um array de 5
             * elementos */
            valores[0] = new int[5];
            /* a segunda posição do array foi
             * inicializada com um array de 2
             * elementos */
            valores[1] = new int[2];
      }
}

Inicializando Elementos em um Loop

Objetos de array têm apenas uma variável pública, que é length, a qual retorna o número de elementos do array. Essa variável normalmente é utilizada para controle de um loop, para que não saia do escopo do array.

public class Loop {    
      public static void main(String[] args) {
            int[] array = new int[5];
            //length é a qtd de elementos do array
            for (int i = 0; i < array.length; i++)
                  System.out.println(array[i]); //0
      }
}


Construindo e Inicializando Arrays em uma Linha

Uma maneira de inicializar e construir um array na mesma linha de código é a seguinte:

int [] d = {6,8,9};
O tamanho desse array será delimitado pelo número de elementos entre chaves. Essa sintaxe também pode ser utilizada para arrays multidimensionais:
int[][] s = {{5,2,4,7}, {9,2}, {3,4}};


Arrays de Primitivos

Arrays primitivos podem receber qualquer valor que pode ser implicitamente combinado com o tipo do array declarado. Por exemplo, um array de int pode receber qualquer valor que caiba em uma variável de 32-bits.

public class AtribuicaoArrayPrimitivos {
      public static void main(String[] args) {
            int[] array = new int[4];
            /* um array de primitivos podem guardar
             * qualquer valor que possa ser
             * implicitamente convertido para o
             * tipo do array */
            byte b = 4;
            char c = 'c';
            short s = 10;
            array[0] = 1;
            array[1] = b;
            array[2] = c;
            array[3] = s;
      }
}

Arrays de Objetos

Se o tipo do array é uma classe, então é possível atribuir aos elementos do array objetos de qualquer subclasse do tipo declarado.
Se o array é do tipo interface, os elementos do array podem ser de qualquer tipo de instância de classe que implemente essa interface. Ou seja, qualquer elemento que passe pelo teste IS-A com o tipo do array pode ser atribuído.


class Carro { }

class Civic extends Carro { }

public class AtribuicaoArrayObjetos {   
      public static void main(String[] args) {
            /* um array de objetos pode guardar
             * referências de objetos do tipo do
             * array ou do tipo de suas subclasses*/
            Carro[] carros = new Carro[2];
            carros[0] = new Carro();
            carros[1] = new Civic();
      }
}

Atribuições de Arrays de Uma Dimensão

Arrays primitivos, uma vez declarados com um tipo, jamais poderão ser instanciados ou receber outro tipo de array. Por exemplo, uma variável byte pode ser atribuída a uma variável int, porque o container de byte é menor que o de int. porém, com arrays de primitivos isso não acontece; não é possível atribuir um array de byte a um array de int; o array de int só pode receber um outro array que seja do tipo int.
Arrays que guardam objetos, ao contrário dos primitivos, não são restritivos, ou seja, um array pode receber um outro array do tipo de sua subclasse. Essa regra também vale para interfaces.

class Pessoa { }

class PFisica extends Pessoa { }

public class SCJP {    
      public static void main(String[] args) {
            int[] arrayInt = new int[2];
            int[] arrayInt2 = new int[3];
            byte[] arrayByte = new byte[2];
            /* arrays de primitivos só podem receber
             * outros arrays do mesmo tipo do array
             * declarado */
            arrayInt = arrayInt2;
            arrayInt = arrayByte;
           
            Pessoa[] arrayP = new Pessoa[2];
            Pessoa[] arrayP2 = new Pessoa[3];
            PFisica[] arrayPF = new PFisica[2];
            /* arrays de objetos podem receber outros
             * arrays do mesmo tipo do array declarado
             * ou arrays do tipo de um subclasse */
            arrayP = arrayP2;
            arrayP = arrayPF;
      }
}

Atribuições de Arrays Multidimensionais

Ao atribuir um array previamente declarado, o array que estiver sendo atribuído deve ter a mesma dimensão que o que está recebendo.


Fonte: SCJP Sun Certified Programmer for Java 6 Study Guide