Java quebra-cabeça visibilidade classe interna
-
23-08-2019 - |
Pergunta
Considere o seguinte caso:
public class A {
public A() { b = new B(); }
B b;
private class B { }
}
A partir de um aviso no Eclipse I citação que: o java compilador emula o A.B. construtor () por um método de acesso sintético. Suponho que o compilador agora vai em frente e cria um extra "debaixo de água" construtor para B.
Eu sinto que este é um pouco estranho: por que a classe B não sejam visíveis como a.k.o. campo em um? E: isso significa que a classe B não é mais privada em tempo de execução? E: por que se comporta a palavra-chave protegido para a classe B diferente
public class A {
public A() { b = new B(); }
B b;
protected class B { }
}
Solução
Classes internas são essencialmente um hack introduzido em Java 1.1. O JVM na verdade não tem qualquer conceito de uma classe interna, e assim o compilador tem que bodge-lo. O compilador gera classe B "fora" da classe A, mas no mesmo pacote, e em seguida, adiciona acessores sintéticos / construtores a ele para permitir que um para obter acesso a ele.
Quando você dá a B um construtor protegido, um pode acessar o construtor já que é no mesmo pacote, sem a necessidade de um construtor sintético a ser adicionado.
Outras dicas
Eu sei que esta questão é agora quase três anos, mas acho que uma parte da pergunta ainda não foi respondida:
E:? Isso significa que a classe B não é mais privada em tempo de execução
Carlos Heubergers comentário sobre skaffmans resposta sugere, classe B
ainda é private
para outras classes no pacote.
Ele provavelmente está certo para a linguagem de programação Java, ou seja, não é possível para se referir a B
classe a partir de uma outra classe. Pelo menos não sem usar reflexão (com o qual também membros de classe privada pode ser acessado a partir do exterior), mas isso é outra questão.
Mas, como a JVM não tem qualquer conceito de uma classe interna (como estados skaffman), eu me perguntava como uma "acessível por apenas uma classe" A visibilidade é realizado no nível de bytecode. A resposta: Não é realizado em todos, para o JVM os olhares classe interna como uma classe privada pacote normal. Isto é, se você escrever bytecode para si mesmo (ou modificar um gerado pelo compilador) você pode acessar classe B
sem problemas.
Você pode acessar todos os métodos sintéticos acessores de todas as classes no mesmo pacote, também. Então, se você atribuir um valor a um campo particular de A
classe em um método de B
classe, um método de acesso sintético com padrão (ou seja, pacote confidencial) a visibilidade é gerado em A
classe (nomeado algo como access$000
) que define o valor para você. Este método é suposto ser chamado apenas de B
classe (e na verdade ele só pode ser chamado de lá usando a linguagem Java). Mas, do ponto de vista JVMs, este é apenas um método como qualquer outro e pode ser chamado por qualquer classe.
Assim, para responder à pergunta:
- A partir das linguagens Java ponto de vista, classe
B
é e estadias privadas. - Do ponto de vista,
B
classe (ou melhor:A$B
classe) JVMs. Não é privado
O acesso de class B
e seu construtor não tem que ser o mesmo. Você pode ter uma classe interna privada com um construtor pacote de escopo, e isso é o que eu costumo fazer.
public class A {
public A() { b = new B(); }
B b;
private class B {
B() { }
}
}
Você precisa usar
this.new B();