Uma coleção de resumos, para ajudar os que precisam daquele empurrão.
Notas:
Nesta declaração indicamos o nome da nossa class, se estende uma classe e se, e quais, interfaces implementa.
public class MyClass [extends SuperClass] [implements InterfaceClass, ...] {
Estas devem ser sempre private
para garantir o encapsulamento do estado
interno do objeto.
private int num;
private String nome;
private XClass outraCena;
private ArrayList<String> nomes;
private ArrayList<XClass> outrasCenas;
Os contrutores permitem instanciar novos objetos da classe. Devem inicializar todos as variáveis de instância.
Este construtor inicializa as variáveis de instância com valores por defeito.
public MyClass(){
this.num = 0;
this.nome = "";
this.outraCena = new XClass();
this.nomes = new ArrayList<>();
this.outrasCenas = new ArrayList<>();
}
Este construtor recebe como parâmetro os valores que as variáveis de instância devem tomar.
(Nota: Uma classe pode ter mais variáveis de instância do que os parâmetros passados neste tipo de construtor, caso, por exemplo, uma destas tenha um valor derivado de outras variáveis.)
As diferentes atribuições feitas neste construtor são explicadas através dos getters/setters mais à frente.
public MyClass(int num, String nome, XClass outraCena,
ArrayList<String> nomes, ArrayList<XClass> outrasCenas){
this.num = num;
this.nome = nome;
this.outraCena = outraCena.clone();
this.nomes = new ArrayList<>(nomes);
this.outrasCenas = new ArrayList<>();
for(XClass cena: outrasCenas){
this.outrasCenas.add(cena.clone());
}
}
Este construtor permite criar uma cópia exata de outra instância deste objeto.
(Nota: Este construtor assume que todos os getters clonam corretamente as variáveis de instância que retornam.)
public MyClass(MyClass myClass){
this.num = myClass.getNum();
this.nome = myClass.getNome();
this.outraCena = myClass.getOutraCena();
this.nomes = myClass.getNomes();
this.outrasCenas = myClass.getOutrasCenas();
}
Os getters permitem aceder às variáveis de instância de uma instância da nossa
classe. Devem ser public
apenas os que queremos que seja possível aceder.
As variáveis são ‘passed by value’, ou seja, o seu valor é copiado. Logo, este get é simples.
(Irá ficar mais claro mais a frente.)
public int getNum(){
return this.num;
}
Uma string é imutável, logo retornar um apontador para este objeto que pertence ao estado interno no nosso objeto não tem problema.
public String getNome(){
return this.nome;
}
Um objeto mutável deve ser clonado para manter o encapsulamento. Se este objeto fosse alterado fora da instância que o retornou, implicaria alterar o estado interno da mesma instância.
(Porque a variável é ‘passed by value’ e esta, na verdade, é um apontador.)
public XClass getOutraCena(){
return this.outraCena.clone();
}
Tem que se criar uma lista nova. Apesar de cada objeto individual da lista ser imutável, a lista em si, não é imutável. Logo, se retornarmos a lista diretamente, novos valores podem ser adicionados à mesma, alterando o estado interno da instância a partir do exterior.
Para isto, podemos fazer uso do construtor da ArrayList
que recebe uma Collection
e copia os valores.
ATENÇÃO: SÓ PODEMOS USAR ESTE construtor PARA LISTAS DE objetos IMUTÁVEIS
public ArrayList<String> getNomes(){
return new ArrayList<>(this.nomes);
}
Ou
public ArrayList<String> getNomes(){
return this.nomes.clone();
}
Como no get anterior, tem que ser criada uma nova lista. Mas, os elementos ao serem adicionados à mesma, têm que ser clonados.
public ArrayList<XClass> getOutrasCenas(){
ArrayList<XClass> newOCenas = new ArrayList<>();
for(XClass cena: this.outrasCenas){
newOCenas.add(cena.clone());
}
return newOCenas;
}
Os setters seguem o mesmo princípio dos getters. Objetos imutáveis e tipos primitivos não têm que ser clonados, tudo o resto sim.
public void setNum(int num){
this.num = num;
}
public void setNome(String nome){
this.nome = nome;
}
public void setOutraCena(XClass outraCena){
this.outraCena = outraCena.clone();
}
public void setNomes(ArrayList<String> nomes){
this.nomes = new ArrayList<>(nomes);
}
/* OU assim
public void setNomes(ArrayList<String> nomes){
this.nomes = nomes.clone();
}
*/
public void setOutrasCenas(ArrayList<XClass> cenas){
ArrayList<XClass> newCenas = new ArrayList<>();
for(XClass cena: cenas){
newCenas.add(cena.clone());
}
this.outrasCenas = newCenas;
}
Nota: Setters de uma lista nem sempre fazem sentido. Dependendo do contexto, pode fazer mais sentido implementar métodos que adicionem ou removam elementos às listas.
Estes métodos devem ser definidos para todas as classes que sejam criadas. Salvo exceções em que sejam inúteis.
O equals é o mais importante, e raramente é inútil.
public boolean equals(Object o){
/*[1]*/ if(this == o) return true;
/*[2]*/ if(o == null || this.getClass() != o.getClass())
return false;
/*[3]*/ MyClass that = (MyClass) o;
/*[4]*/ return this.num == that.getNum()
&& this.nome.equals(that.getNome())
&& this.outraCena.equals(that.getOutraCena())
&& this.nomes.equals(that.getNomes())
&& this.outrasCenas.equals(that.getOutrasCenas());
}
Análise do código:
==
.equals
das mesmas.O toString é importante para efeitos de debug. Pode também ser adaptado para aplicações de terminal.
public String toString(){
StringBuffer sb = new StringBuffer("MyClass: ");
sb.append("Num: ").append(this.num).append(", ");
sb.append("Nome: ").append(this.nome).append(", ");
sb.append("Outra Cena: ").append(this.outraCena).append(", ");
sb.append("Nomes: ").append(this.nomes).append(", ");
sb.append("Outras Cenas: ").append(this.outrasCenas).append(", ");
return sb.toString();
}
O clone pode ser implementado tirando partido do construtor de cópia.
public MyClass clone(){
return new MyClass(this);
}
Nota: Objetos imutáveis não devem implementar este método.
Lista dos principais objetos imutáveis disponíveis: