Não estive em uma situação em que um erro do compilador causado por essas palavras-chave tivesse me salvado de um bug.
Não é demais salvar os autores de aplicativos dos erros, mas permitir que os autores da biblioteca decidam quais partes de sua implementação estão comprometidas em manter.
Se eu tiver uma biblioteca
class C {
public void foo() { ... }
private void fooHelper() { /* lots of complex code */ }
}
Talvez eu queira substituir foo
a implementação e possivelmente mudar de fooHelper
maneiras radicais. Se várias pessoas decidiram usarfooHelper
várias apesar de todos os avisos na minha documentação, talvez eu não consiga fazer isso.
private
permite que os autores das bibliotecas dividam as bibliotecas em métodos de tamanho gerenciável (e private
classes auxiliares) sem o medo de serem forçados a manter esses detalhes internos por anos.
O que faria valer a pena para o compilador impor a ocultação de informações?
Em uma nota lateral, em Java private
não é imposta pelo compilador, mas pelo verificador de bytecode Java .
A reflexão pode substituir esse mecanismo? O que faria valer a pena para o compilador impor a ocultação de informações?
Em Java, não apenas a reflexão pode substituir esse mecanismo. Existem dois tipos de private
em Java. O tipo de private
impedimento de uma classe externa acessar os private
membros de outra classe externa que é verificado pelo verificador de bytecode, mas também os private
que são usados por uma classe interna por meio de um método acessador sintético privado de pacote, como em
public class C {
private int i = 42;
public class B {
public void incr() { ++i; }
}
}
Como a classe B
(realmente chamada C$B
) usa i
, o compilador cria um método acessador sintético que permite B
acessar C.i
de uma maneira que ultrapassa o verificador de bytecode. Infelizmente, como ClassLoader
permite criar uma classe a partir de a byte[]
, é bastante simples obter informações particulares que C
foram expostas a classes internas criando uma nova classe no C
pacote de que é possível seC
o jarro não tiver sido selado.
A private
aplicação adequada requer coordenação entre os carregadores de classe, o verificador de código de bytes e a política de segurança que pode impedir o acesso reflexivo a partes privadas.
Pode ser usado para impedir que o estado secreto de uma classe seja atacado?
Sim. A "decomposição segura" é possível quando os programadores podem colaborar enquanto preservam as propriedades de segurança de seus módulos - não preciso confiar no autor de outro módulo de código para não violar as propriedades de segurança do meu módulo.
Linguagens de recursos de objetos como Joe-E usam ocultação de informações e outros meios para tornar possível a decomposição segura:
Joe-E é um subconjunto da linguagem de programação Java projetada para suportar a programação segura de acordo com a disciplina de capacidade do objeto. O Joe-E tem como objetivo facilitar a construção de sistemas seguros, bem como facilitar as análises de segurança dos sistemas criados no Joe-E.
O documento vinculado a essa página fornece um exemplo de como a private
aplicação possibilita a decomposição segura.
Fornecendo encapsulamento seguro.
Figura 1. Um recurso de registro somente anexado.
public final class Log {
private final StringBuilder content;
public Log() {
content = new StringBuilder();
}
public void write(String s) {
content.append(s);
}
}
Considere a Fig. 1, que ilustra como alguém pode construir um recurso de registro somente para acréscimo. Desde que o restante do programa seja escrito em Joe-E, um revisor de código pode ter certeza de que as entradas de log podem ser adicionadas apenas e não podem ser modificadas ou removidas. Essa revisão é prática porque requer apenas inspeção da Log
classe e não requer revisão de nenhum outro código. Conseqüentemente, a verificação dessa propriedade requer apenas um raciocínio local sobre o código de log.