Programação Orientada a Objetos: Uma Abordagem com Java/Princípios da programação na linguagem Java/Operações

Operações envolvendo objetosEditar

Antes de poder fazer qualquer operação envolvendo um objeto de qualquer classe, é necessário primeiro criar esse objeto. Observe que a simples declaração de um objeto de uma classe Cls, como em

Cls obj;

não cria o objeto, mas simplesmente uma variável que poderá ser utilizada para referenciar o objeto dessa classe.

A criação de um objeto dá-se através da aplicação do operador new. Dada uma classe Cls, é possível (em princípio) criar um objeto dessa classe usando esse operador:

Cls obj = new Cls();

O “método” (cujo nome que precede os parênteses) à direita do operador new é um construtor da classe Cls. Um construtor é um (pseudo-)método especial, definido para cada classe. O corpo desse método determina as atividades associadas à inicialização de cada objeto criado. Assim, o construtor é apenas invocado no momento da criação do objeto por intermédio do operador new.

A assinatura de um construtor diferencia-se das assinaturas dos outros métodos por não ter nenhum tipo de retorno — nem mesmo void. Além disto, o nome do construtor deve sempre ser o próprio nome da classe. O construtor pode receber argumentos, como qualquer método. Usando o mecanismo de sobrecarga, mais de um construtor pode ser definido para uma classe.

Toda classe tem pelo menos um construtor sempre definido. Se nenhum construtor for explicitamente definido pelo programador da classe, um construtor padrão, que não recebe argumentos, é criado pelo compilador Java. No entanto, se o programador da classe criar pelo menos um método construtor, esse construtor padrão não será criado automaticamente — se o desenvolvedor assim o desejar, deverá criar um construtor sem argumentos explicitamente.

No momento em que um construtor é invocado, a seguinte sequência de ações é executada para a criação de um objeto:

  1. O espaço para o objeto é alocado e seu conteúdo é inicializado (bitwise, ou seja, bit a bit da estrutura interna de cada elemento) com zeros.
  2. O construtor da classe base é invocado.
  3. Os membros da classe são inicializados para o objeto, seguindo a ordem em que foram declarados na classe.
  4. O restante do corpo do construtor é executado.

Seguir essa sequência é uma necessidade de forma a garantir que, quando o corpo de um construtor esteja sendo executado, o objeto já terá à disposição as funcionalidades mínimas necessárias, quais sejam aquelas definidas por seus ancestrais. O primeiro passo garante que nenhum campo do objeto terá um valor arbitrário, que possa tornar erros de não inicialização difíceis de detectar. Esse passo é que determina os valores default para atributos de tipos primitivos.

Uma vez que um objeto tenha sido criado e haja uma referência válida para ele, é possível solicitar que ele execute métodos que foram definidos para objetos dessa classe. A aplicação de um método meth(int), definido em uma classe Cls, a um objeto obj, construído a partir da especificação de Cls, se dá através da construção

obj.meth(varint);

onde varint é uma expressão ou variável inteira anteriormente definida.

Em uma linguagem tradicional, a forma correspondente seria invocar uma função ou procedimento passando como argumento a estrutura de dados sobre a qual as operações teriam efeito:

meth(obj, varint);

Esse “atributo implícito” — a referência para o próprio objeto que está ativando o método — pode ser utilizado no corpo dos métodos quando for necessário fazê-lo explicitamente. Para tanto, a palavra-chave this é utilizada.

Reforçando, quando se declara uma variável cujo tipo é o nome de uma classe, como em

String nome;

não está se criando um objeto dessa classe, mas simplesmente uma referência para um objeto da classe String, a qual inicialmente não faz referência a nenhum objeto válido. Quando um objeto dessa classe é criado, obtém-se uma referência válida, que é armazenada na variável cujo tipo é o nome da classe do objeto. Por exemplo, quando cria-se uma string como em

nome = new String("POO/Java");

nome é uma variável que armazena uma referência válida para um objeto específico da classe String — o objeto cujo conteúdo é a string POO/Java.

É importante ressaltar que a variável nome mantém apenas a referência para o objeto e não o objeto em si. Assim, uma atribuição como

String outroNome = nome;

não cria outro objeto, mas simplesmente uma outra referência para o mesmo objeto.

A linguagem Java permite que o programador crie e manipule objetos explicitamente. Porém, a remoção de objetos em Java é manipulada automaticamente pelo ambiente de execução Java, usando um mecanismo de coleta de lixo (garbage collector). Esse coletor de lixo é um processo de baixa prioridade que permanece verificando quais objetos não têm nenhuma referência válida, retomando o espaço despendido para cada um desses objetos. Dessa forma, o programador não precisa se preocupar com a remoção explícita de objetos.

Outra operação que pode envolver um objeto é sua verificação de tipo. Dado um objeto obj e uma classe Cls, é possível verificar dinamicamente (durante a execução do método) se o objeto pertence ou não à classe usando o operador instanceof. Esse operador retorna true se o objeto à esquerda do operador é da classe especificada à direita do operador. Assim,

obj instanceof Cls

retorna true se obj for da classe Cls.