- Comportamento de Métodos e Passagem de Parâmetros
public class DemoParametros {
static void tentarModificarTexto(String param) {
param = "novo_valor";
}
static void alterarElementos(String[] lista) {
for (int j = 0; j < lista.length; j++) {
lista[j] = lista[j].concat("_" + j);
}
}
public static void main(String[] args) {
String txt = "original";
tentarModificarTexto(txt);
System.out.println(txt);
alterarElementos(args);
System.out.println(Arrays.toString(args));
}
}
Análise do comportamento:
- O método
tentarModificarTextorecebe uma String como parâmetro e tenta reatribuir seu valor, porém essa alteração não afeta a variável original na chamada. Isso ocorre porque em Java a passagem de parâmetros é sempre por valor — para tipos referenciais, é passada uma cópia da referência. Ao reatribuirparam, apenas a cópia local da referência passa a apontar para outro objeto, sem impactar a referência original. - O método
alterarElementospercrore o array recebido e concatena o índice a cada elemento. Como a referência aponta para o mesmo objeto array em memória, as modificações nos elementos afetam o array original. - Os valores de
argsvêm dos argumentos passados na linha de comando ao executar o programa:java DemoParametros valor1 valor2.
- Semântica de Referências em Arrays
int[] dados = new int[3];
dados[0] = 1;
dados[1] = 1;
int[] copiaRef = dados;
dados[0] = 2;
System.out.println(Arrays.toString(dados));
System.out.println(Arrays.toString(copiaRef));
A saída será [2, 1, 0] para ambas as linhas. A atribuição int[] copiaRef = dados não cria um novo array, mas sim uma nova referência para o mesmo objeto em memória. Logo, qualquer modificação feita através de uma variável é visível pela outra.
String[] nomes = {"alfa", "beta", "gama"};
nomes[1] = "delta";
System.out.println(Arrays.toString(nomes));
Embora String seja imutável em Java, o código acima funciona porque não está modificando o conteúdo de uma String, e sim trocando a referência armazenada na posição 1 do array — de "beta" para "delta". A imutabilidade da String permanece intacta.
- Arrays Multidimensionais Irregulares
Em Java, ao declarar int[5][], apenas a primeira dimensão é fixada com tamanho 5. A segunda dimensão pode ter comprimentos distintos para cada linha:
public class MatrizIrregular {
public static void main(String[] args) {
int[][] matriz = new int[5][];
matriz[0] = new int[]{1, 2, 3};
matriz[1] = new int[]{4, 5};
matriz[2] = new int[]{6, 7, 8, 9};
matriz[3] = new int[]{10};
matriz[4] = new int[]{11, 12, 13, 14, 15};
for (int[] linha : matriz) {
for (int valor : linha) {
System.out.print(valor + " ");
}
System.out.println();
}
}
}
Este padrão é conhecido como array jagged (irregular), onde cada sub-array pode ter um tamanho diferente, oferecendo flexibilidade na representação de dados não uniformes.
- Classes, Objetos e Encapsulamento
Classe vs. Objeto: Uma classe é uma abstração que define a estrutura e o comportamento de um conjunto de entidades. Um objeto é uma instância concreta dessa abstração, ocupando espaço em memória durante a execução.
Math: A classe Math não pode ser instanciada — seu construtor é privado. Todos os seus membros são estáticos, acessados diretamente via nome da classe.
String e encapsulamento: A classe String mantém seu array interno de caracteres como private final char value[], garantindo imutabilidade. Se esse campo fosse público, qualquer código poderia alterar o conteúdo, quebrando o contrato de imutabilidade. Já métodos como length(), substring() e charAt() são públicos, permitindo que usuários consultem e manipulem Strings de forma controlada sem comprometer sua integridade interna.
- Padrão Setter/Getter e Encapsulamento
Embora atributos public ofereçam acesso direto, o padrão de accessors (getters/setters) é amplamente adotado por várias razões:
- Validação de dados: Um setter pode rejeitar valores inválidos antes de atribuí-los, como verificar se uma idade não é negativa.
- Controle de acesso: Pode-se expor apenas o getter, criando propriedades somente leitura, ou apenas o setter para propreidades somente escrita.
- Flexibilidade de implementação: Se a representação interna de um atributo mudar, apenas os accessors precisam ser ajustadso, sem impactar quem consome a classe.
- Lógica adicional: Pode-se adicionar notificações, logs ou cálculos derivados dentro dos accessors.
O encapsulamento é o princípio de ocultar detalhes internos e expor apenas interfaces controladas. Os accessors são a materialização prática desse princípio.
- Inicialização de Atributos em Objetos
Os atributos de um objeto podem ser inicializados em diferentes momentos:
- Na declaração:
private int contador = 0; - No construtor: atribuição dentro da lógica de inicialização
- Em blocos de inicialização: blocos
{ }executados antes do construtor - Após a instanciação: via setters ou métodos de configuração
public class ExemploInicializacao {
private int valor = 10; // na declaração
private String nome;
{
nome = "padrão"; // bloco de inicialização
}
public ExemploInicializacao(String nome) {
this.nome = nome; // no construtor
}
public void configurarValor(int v) {
this.valor = v; // pós-instanciação
}
}
- Escopos de Acesso e Encapsulamento
Os modificadores de acesso em Java definem o escopo de visibilidade de membros, sendo fundamentais para o encapsulamento:
private: Restrito à própria classe. Esconde a implementação interna, protegendo dados de manipulação externa direta.protected: Acessível pela classe, suas subclasses e classes do mesmo pacote. Oferece um equilíbrio entre reutilização em hierarquias de herança e proteção contra acesso irrestrito.public: Sem restrições de acesso. Deve ser reservado para a interface pública da classe — métodos que representam o contrato de uso.- Default (sem modificador): Acessível apenas dentro do mesmo pacote.
A combinação estratégica desses modificadores permite construir APIs robustas: dados internos ficam privados, métodos utilitários internos são protegidos, e apenas operações relevantes são expostas publicamente.