Um guia para criar objetos em Java
1. Visão geral
Simplificando, antes que possamos trabalhar com um objeto na JVM, ele deve ser inicializado.
Nas seções a seguir, daremos uma olhada em várias maneiras de inicializar tipos e objetos primitivos.
2. Declaração vs. Inicialização
Vamos começar verificando se estamos na mesma página.
Declaration is the process of defining the variable junto com seu tipo e nome.
Aqui, estamos declarando a variávelid:
int id;
A inicialização, por outro lado, trata da atribuição de um valor; por exemplo:
id = 1;
Para demonstrar, vamos criar uma classeUser com as propriedadesnameeid:
public class User implements {
private String name;
private int id;
// standard constructor, getters, setters,
}
A seguir, veremos que a inicialização funciona de maneira diferente dependendo do tipo de campo que estamos inicializando.
3. Objetos vs. Primitivas
Java fornece dois tipos de representação de dados: tipos primitivos e tipos de referência. Nesta seção, discutiremos as diferenças entre os dois com relação à inicialização.
Java possui oito tipos de dados internos, chamados de tipos primitivos Java; variáveis desse tipo mantêm seus valores diretamente.
Os tipos de referência mantêm referências a objetos (instâncias de classes). Unlike primitive types that hold their values in the memory where the variable is allocated, references don’t hold the value of the object they refer to.
Em vez disso,a reference points to an object by storing the memory address where the object is located.
Observe que o Java não nos permite descobrir qual é o endereço da memória física. Em vez disso, só podemos usar a referência para se referir ao objeto.
Vamos dar uma olhada em um exemplo que declara e inicializa um tipo de referência fora de nossa classeUser:
@Test
public void whenIntializedWithNew_thenInstanceIsNotNull() {
User user = new User();
assertThat(user).isNotNull();
}
Como podemos ver aqui, uma referência pode ser atribuída a um novo usando a palavra-chavenew,, que é responsável por criar o novo objetoUser.
Vamos continuar aprendendo mais sobre a criação de objetos.
5. Criando objetos
Diferentemente das primitivas, a criação de objetos é um pouco mais complexa. Isso ocorre porque não estamos apenas adicionando valor ao campo; em vez disso, disparamos a inicialização usando a palavra-chavenew. Isso, por sua vez, chama um construtor e inicializa o objeto na memória.
Vamos discutir os construtores e a palavra-chavenew em mais detalhes.
A palavra-chavenew éresponsible for allocating memory for the new object through a constructor.
A constructor is typically used to initialize instance variables representing the main properties of the created object.
Se não fornecermos um construtor explicitamente, o compilador criará um construtor padrão que não tem argumentos e apenas aloca memória para o objeto.
A class can have many constructors as long as their parameters lists are different (overload). Cada construtor que não chama outro construtor na mesma classe tem uma chamada para seu construtor pai, tenha sido escrito explicitamente ou inserido pelo compilador por meio desuper().
Vamos adicionar um construtor à nossa classeUser:
public User(String name, int id) {
this.name = name;
this.id = id;
}
Agora podemos usar nosso construtor para criar um objetoUser com valores iniciais para suas propriedades:
User user = new User("Alice", 1);
6. Escopo Variável
Nas seções a seguir, daremos uma olhada nos diferentes tipos de escopos nos quais uma variável em Java pode existir e como isso afeta o processo de inicialização.
6.1. Variáveis de instância e classe
Instance and class variables don’t require us to initialize them. Assim que declaramos essas variáveis, elas recebem um valor padrão da seguinte forma:
Agora, vamos tentar definir algumas variáveis relacionadas à instância e à classe e testar se elas têm um valor padrão ou não:
@Test
public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() {
User user = new User();
assertThat(user.getName()).isNull();
assertThat(user.getId() == 0);
}
6.2. Variáveis locais
Local variables must be initialized before use, pois eles não têm um valor padrão e o compilador não nos permite usar um valor não inicializado.
Por exemplo, o código a seguir gera um erro do compilador:
public void print(){
int i;
System.out.println(i);
}
7. A palavra-chaveFinal
A palavra-chavefinal aplicada a um campo significa que o valor do campo não pode mais ser alterado após a inicialização. Dessa forma, podemos definir constantes em Java.
Vamos adicionar uma constante à nossa classeUser:
private static final int YEAR = 2000;
As constantes devem ser inicializadas quando são declaradas ou em um construtor.
8. Inicializadores em Java
Em Java, uminitializer is a block of code that has no associated name or data typee é colocado fora de qualquer método, construtor ou outro bloco de código.
Java oferece dois tipos de inicializadores, inicializadores estático e de instância. Vamos ver como podemos usar cada um deles.
8.1. Inicializadores de instância
Podemos usá-los para inicializar variáveis de instância.
Para demonstrar, vamos fornecer um valor para um usuárioid usando um inicializador de instância em nossa classeUser:
{
id = 0;
}
8.2. Bloco de inicialização estática
Um inicializador estático ou bloco estático - é um bloco de código que é usado para inicializar camposstatic. Em outras palavras, é um inicializador simples marcado com a palavra-chavestatic:
private static String forum;
static {
forum = "Java";
}
9. Ordem de inicialização
Ao escrever um código que inicialize diferentes tipos de campos, é claro, temos que ficar de olho na ordem de inicialização.
Em Java, a ordem das instruções de inicialização é a seguinte:
-
variáveis estáticas e inicializadores estáticos em ordem
-
variáveis de instância e inicializadores de instância em ordem
-
construtores
10. Ciclo de Vida do Objeto
Agora que aprendemos como declarar e inicializar objetos, vamos descobrir o que acontece com os objetos quando eles não estão em uso.
Diferente de outras linguagens em que precisamos nos preocupar com a destruição de objetos, o Java cuida de objetos obsoletos por meio de seu coletor de lixo.
All objects in Java are stored in our program’s heap memory. De fato, o heap representa um grande conjunto de memória não utilizada, alocada para nosso aplicativo Java.
Por outro lado, ogarbage collector is a Java program that takes care of automatic memory management excluindo objetos que não são mais alcançáveis.
Para um objeto Java se tornar inacessível, ele precisa encontrar uma das seguintes situações:
-
O objeto não possui mais referências apontando para ele
-
Todas as referências que apontam para o objeto estão fora do escopo
Em conclusão, um objeto é criado primeiro a partir de uma classe, geralmente usando a palavra-chavenew.. Então, o objeto vive sua vida e nos fornece acesso a seus métodos e campos.
Finalmente, quando não é mais necessário, o coletor de lixo o destrói.
11. Outros métodos para criar objetos
Nesta seção, daremos uma breve olhada emmethods other than new keyword to create objects and how to apply them, specifically reflection, cloning, and serialization.
Reflection is a mechanism we can use to inspect classes, fields, and methods at run-time. Aqui está um exemplo de criação de nosso objetoUser usando reflexão:
@Test
public void whenInitializedWithReflection_thenInstanceIsNotNull()
throws Exception {
User user = User.class.getConstructor(String.class, int.class)
.newInstance("Alice", 2);
assertThat(user).isNotNull();
}
Neste caso, estamos usando reflexão para encontrar e invocar um construtor da classeUser.
O próximo método,cloning, is a way to create an exact copy of an object. Para isso, nossa classeUser deve implementar a interfaceCloneable:
public class User implements Cloneable { //... }
Agora podemos usar o métodoclone() para criar um novo objetoclonedUser que tem os mesmos valores de propriedade do objetouser:
@Test
public void whenCopiedWithClone_thenExactMatchIsCreated()
throws CloneNotSupportedException {
User user = new User("Alice", 3);
User clonedUser = (User) user.clone();
assertThat(clonedUser).isEqualTo(user);
}
Também podemos usar a classesun.misc.Unsafe para alocar memória para um objeto sem chamar um construtor:
User u = (User) unsafeInstance.allocateInstance(User.class);
12. Conclusão
Neste tutorial, abordamos a inicialização de campos em Java. Descobrimos diferentes tipos de dados em Java e como usá-los. Também analisamos várias maneiras de criar objetos em Java.
A implementação completa deste tutorial pode ser encontradaover on Github.