Por que um membro privado é acessível em um método estático?


25

A seguir, é pseudo-código, tentei em Java e PHP e ambos funcionaram:

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

Por que você pode fazer isso no paradigma OOP e para que serve?


6
Por que não seria? Em Java, os membros privados não são privados para a instância, mas privados para o arquivo de origem . O primeiro uso a se lembrar é equalsque é necessário verificar os campos particulares de outra instância. (Posting como comentário, como este é curto, e nada sobre a OOP-ness desta abordagem)
Ordous

2
Observe que os métodos estáticos não possuem a this, portanto, os únicos objetos de sua própria classe em que eles podem chegar são os que eles mesmos criam (ou são passados ​​como parâmetro). Portanto, se você considera isso uma violação do encapsulamento ou uma falha de segurança, não é muito grande e pode não valer a pena ser corrigida.
precisa

4
Não sei por que isso foi prejudicado. A pergunta pode ser trivial (ish), mas o OP passou pelo problema de testar o comportamento em dois idiomas antes de perguntar. É muito mais esforço do que normalmente vemos nos recém-chegados.
22414 yannis

1
@YannisRizos concordou e, na verdade, não acho que a pergunta seja trivial. Tem implicações para seguir o "princípio do menor privilégio". Isso significa que as funções auxiliares que não precisam de acesso aos internos de uma instância devem ser definidas em uma classe separada e, inversamente, quando essa convenção for seguida, você saberá que sempre que existe um método estático na mesma classe, ele está acessando o estado interno.
Doval

1
De fato, quando perguntei aos meus colegas, todos disseram que isso é impossível. É por isso que eu não pensei que é trivial
Ben

Respostas:


17

Em Java, variáveis ​​privadas são visíveis para toda a classe. Eles podem ser acessados ​​a partir de métodos estáticos e de outras instâncias da mesma classe.

Isso é, por exemplo, útil em métodos de fábrica . Um método de fábrica geralmente inicializa um objeto que é tão complexo que você não deseja deixá-lo no código do aplicativo. Para fazer a inicialização, o método factory geralmente precisa acessar os internos da classe que você não deseja expor. Ser capaz de acessar diretamente as variáveis ​​privadas facilita sua vida.

No entanto, quando você deseja ocultar os detalhes de implementação de uma classe, mesmo de métodos estáticos ou de outras instâncias dessa classe, pode seguir o padrão de dados da classe privada . Coloque todas as variáveis ​​privadas de uma classe em uma classe interna privada e delegue quaisquer getters ou setters a getters e setters dessa classe interna.

Outra opção é definir uma interface para a classe que declare todos os métodos públicos da classe e, em seguida, referencie a classe sob essa interface sempre que possível. Uma referência ao tipo de interface não pode ser usada para acessar diretamente qualquer coisa não declarada na interface, não importa onde (exceto com reflexão, é claro). Quando você usa uma linguagem de programação orientada a objetos que não possui interfaces (como C ++, por exemplo), elas podem ser simuladas com uma classe base abstrata que é herdada pela classe real.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}

Você consegue pensar em uma situação em que o padrão de dados de classe privada é útil? Pessoalmente, uso classes internas apenas em GUI, como configurações (Swing, etc) ou classes internas estáticas em exercícios de codificação, pois não quero que um exercício abranja vários arquivos de origem.
InformedA

1
Ocultar o interior de uma classe de outras instâncias tira uma das vantagens que as classes têm sobre as interfaces sem recuperar nada em troca. Uma solução mais simples e flexível é usar apenas uma interface.
Doval

3

Algumas linguagens e estruturas de tempo de execução (por exemplo, Java, .NET) pressupõem que qualquer pessoa que esteja compilando o código para uma classe específica possa confiar em não usar nenhum membro privado de qualquer instância dessa classe de maneiras que possam prejudicar sua correta Operação. Outras linguagens e estruturas são mais restritivas a esse respeito e não permitem o acesso a membros particulares de uma instância, exceto pelo código em execução nessa instância . Ambos os projetos têm vantagens e desvantagens.

A maior vantagem de permitir que qualquer código dentro de uma classe acesse membros particulares de qualquer instância é que há casos em que esse nível de acesso é apropriado e o privatetrabalho dessa maneira elimina a necessidade de ter um qualificador de acesso diferente disponível para esse fim ou caso contrário, force o código a expor os membros mais amplamente do que seria ideal.

Uma vantagem de proibir esse acesso (como no COM) (Microsoft Common Object Model) é que ele permite que o código externo trate as classes como interfaces. Se uma classe ImmutableMatrixcontiver um double[][]campo de apoio privado ou protegido , e se o código dentro da classe examinar a matriz de apoio de outras instâncias, não será possível definir uma classe não suportada por matriz (por exemplo ZeroMatrix, IdentityMatrix) que o código externo possa usar como um Immutable2dMatrix, sem que a classe tendo incluindo o campo de suporte. Se nada dentro Immutable2dMatrixusar membros privados de qualquer instância que thisnão seja, seria possível renomear a classe para ImmutableArrayBackedMatrixe definir uma nova ImmutableMatrixclasse abstrata que poderia ter ImmutableArrayBackedMatrix, como subtipos, as classes acima mencionadas sem o array.

Observe que essa refatoração não seria impedida se o idioma "permitisse" ImmutableMatrixexaminar a matriz de apoio para outras instâncias this, a menos que o idioma aproveitasse essa capacidade e realmente examinasse instâncias externas. O principal efeito de um idioma restringir esse uso é que ele fará o compilador gritar imediatamente em qualquer tentativa de escrever código que não seja passível de refatoração.


2

Java não é estritamente uma linguagem orientada a objetos, mas uma linguagem baseada em classe - a classe determina as operações e o acesso ao comportamento, e não a instância.

Portanto, não se surpreenda demais porque isso permite que você faça coisas que não são estritamente orientadas a objetos.

Como o método está no mesmo escopo de classe da instância, ele tem acesso total a membros privados. Regras semelhantes governam instâncias de classes internas que acessam dados de instâncias de classes externas - uma instância de uma classe interna pode acessar membros privados da classe externa.

Isso é herdado do C ++, onde é útil para criar construtores de copiar e mover. Também é útil para comparar ou combinar dois objetos em que seu valor depende de membros que não são acessíveis publicamente de maneira eficiente (por exemplo, o getter para uma matriz em Java deve copiar a matriz para que o código do cliente não possa modificá-lo, alterando o estado interno do objeto, mas ter que copiar matrizes para comparar a igualdade do objeto não é eficiente)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.