Por que não podemos ter um método estático em uma classe interna não estática?
Se eu tornar estática a classe interna, ela funcionará. Por quê?
java
class
static
inner-classes
Rahul Garg
fonte
fonte
static
.")Respostas:
Como uma instância de uma classe interna está implicitamente associada a uma instância de sua classe externa, ela não pode definir nenhum método estático. Como uma classe aninhada estática não pode se referir diretamente a variáveis ou métodos de instância definidos em sua classe anexa, ela pode usá-los apenas por meio de uma referência a objeto, é seguro declarar métodos estáticos em uma classe aninhada estática.
fonte
A.B.sync(X)
ou até mesmo (de dentro de A)B.sync(x)
?Não há muito sentido em permitir um método estático em uma classe interna não estática; como você acessaria? Você não pode acessar (pelo menos inicialmente) uma instância de classe interna não estática sem passar por uma instância de classe externa. Não existe uma maneira puramente estática de criar uma classe interna não estática.
Para uma classe externa
Outer
, você pode acessar um método estáticotest()
como este:Para uma classe interna estática
Inner
, você pode acessar seu método estáticoinnerTest()
assim:No entanto, se
Inner
não for estático, agora não há uma maneira puramente estática de fazer referência ao métodoinnertest
. Classes internas não estáticas estão vinculadas a uma instância específica de sua classe externa. Uma função é diferente de uma constante, na medida em que uma referência aOuter.Inner.CONSTANT
é garantida como inequívoca de uma maneira que uma função chamaOuter.Inner.staticFunction();
não é. Digamos que você tenhaInner.staticFunction()
essas chamadasgetState()
, definidas emOuter
. Se você tentar invocar essa função estática, agora terá uma referência ambígua à classe Inner. Ou seja, em qual instância da classe interna você invoca a função estática? Importa. Veja, não há uma maneira verdadeiramente estática de referenciar esse método estático, devido à referência implícita ao objeto externo.Paul Bellora está certo de que os designers de linguagem poderiam ter permitido isso. Eles teriam que impedir cuidadosamente qualquer acesso à referência implícita à classe externa nos métodos estáticos da classe interna não estática. Neste ponto, qual é o valor de ser uma classe interna se você não pode fazer referência à classe externa, exceto estaticamente? E se o acesso estático está bom, por que não declarar estática toda a classe interna? Se você simplesmente tornar a própria classe interna estática, não terá uma referência implícita à classe externa e não terá mais essa ambiguidade.
Se você realmente precisa de métodos estáticos em uma classe interna não estática, provavelmente precisará repensar seu design.
fonte
Outer.Inner i = new Outer().new Inner();
Além disso, classes internas são autorizados a declarar estáticos constantes de acordo com JLS §15.28.Outer.Inner.staticMethod()
exatamente como pode acessarOuter.Inner.CONSTANT
. "Você não pode acessar ... uma instância de classe interna não estática sem passar por uma instância de classe externa." Por que você precisaria de uma instância? Você não precisa de uma instânciaOuter
para ligarOuter.staticMethod()
. Eu sei que isso é muito exigente, mas meu argumento é que não faz sentido enquadrar sua resposta dessa maneira. IMHO os designers de linguagem poderiam ter permitido se quisessem.Outer.Inner.CONSTANT
eOuter.Inner.staticMethod()
é que uma referência a uma constante não tem chance de referenciar implicitamente a instânciaOuter
em queInner
foi instanciada. Todas as referências paraOuter.staticMethod()
compartilhar o mesmo estado exato. Todas as referências paraOuter.Inner.CONSTANT
compartilhar o mesmo estado exato. No entanto, as referências aOuter.Inner.staticMethod()
são ambíguas: O estado "estático" não é realmente estático, devido à referência implícita à classe externa em cada instância deInner
. Não existe uma maneira realmente inequívoca e estática de acessá-lo.Outer.this
. Concordo com os designers de linguagem Java que não há razão para permitir métodos estáticos ou campos estáticos não finais nas classes internas, porque tudo em uma classe interna deve estar dentro do contexto da classe envolvente.Eu tenho uma teoria que pode ou não estar correta.
Primeiro, você deve saber algumas coisas sobre como as classes internas são implementadas em Java. Suponha que você tenha essa classe:
Quando você o compila, o bytecode gerado terá a aparência de que você escreveu algo como isto:
Agora, se permitimos métodos estáticos em classes internas não estáticas, convém fazer algo assim.
... o que parece bastante razoável, pois a
Inner
classe parece ter uma encarnação porOuter
exemplo. Mas, como vimos acima, as classes internas não estáticas são realmente apenas açúcar sintático para classes "internas" estáticas; portanto, o último exemplo seria aproximadamente equivalente a:... o que claramente não vai funcionar, pois
this$0
não é estático. Isso explica por que métodos estáticos não são permitidos (embora você possa argumentar que você pode permitir métodos estáticos, desde que não façam referência ao objeto anexo) e por que você não pode ter campos estáticos não finais ( seria contra-intuitivo se instâncias de classes internas não estáticas de diferentes objetos compartilhassem "estado estático"). Também explica por que os campos finais são permitidos (desde que não façam referência ao objeto anexo).fonte
public static double sinDeg(double theta) { ... }
uma aula interna de matemática?O único motivo é "não obrigatório", então por que se preocupar em apoiá-lo?
Sintaticamente, não há razão para proibir uma classe interna de ter membros estáticos. Embora uma instância de
Inner
esteja associada a uma instância deOuter
, ainda é possível usarOuter.Inner.myStatic
para referenciar um membro estático deInner
se o java decidir fazer isso.Se você precisar compartilhar algo entre todas as instâncias
Inner
, basta colocá-losOuter
como membros estáticos. Isso não é pior do que você usa membros estáticosInner
, ondeOuter
ainda pode acessar qualquer membro privadoInner
(não melhora o encapsulamento).Se você precisar compartilhar algo entre todas as instâncias
Inner
criadas por umouter
objeto, faz mais sentido colocá-las naOuter
classe como membros comuns.Não concordo com a opinião de que "uma classe aninhada estática é basicamente apenas uma classe de nível superior". Eu acho que é melhor considerar realmente uma classe aninhada estática / classe interna como parte da classe externa, porque eles podem acessar os membros privados da classe externa. E membros da classe externa também são "membros da classe interna". Portanto, não há necessidade de oferecer suporte a membro estático na classe interna. Um membro comum / estático na classe externa será suficiente.
fonte
De: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
A explicação da Oracle é superficial e ondulada. Como não há razão técnica ou sintática para antecipar membros estáticos dentro de uma classe interna (é permitido em outras linguagens como C #), a motivação dos designers de Java era provavelmente gosto conceitual e / ou uma questão de conveniência técnica.
Aqui está a minha especulação:
Diferentemente das classes de nível superior, as classes internas são dependentes da instância: uma instância da classe interna é associada a uma instância de cada uma de suas classes externas e tem acesso direto a seus membros. Essa é a principal motivação para tê-los em Java. Expressa de outra maneira: uma classe interna é destinada à instanciação no contexto de uma instância de classe externa. Sem uma instância de classe externa, uma classe interna não deve ser mais utilizável do que os outros membros da instância externa. Vamos nos referir a isso como o espírito dependente da instância das classes internas.
A própria natureza dos membros estáticos (que NÃO são orientados a objetos) entra em conflito com o dependente da instância espírito das classes internas (que é orientado a objetos) porque você pode fazer referência / chamar um membro estático de uma classe interna sem uma instância de classe externa, usando o nome qualificado da classe interna.
As variáveis estáticas, em particular, podem ofender de outra maneira: duas instâncias de uma classe interna associadas a instâncias diferentes da classe externa compartilhariam variáveis estáticas. Como as variáveis são um componente do estado, as duas instâncias da classe interna compartilhariam o estado independentemente das instâncias da classe externa às quais estão associadas. Não é inaceitável que variáveis estáticas funcionem dessa maneira (nós as aceitamos em Java como um comprometimento sensível à pureza do OOP), mas é possível que haja uma ofensa mais profunda ao permitir-lhes em classes internas cujas instâncias já estão associadas a instâncias de classe externa por design. Proibir membros estáticos dentro das classes internas em favor do espírito dependente da instância colhe o bônus adicional de impedir esta ofensa mais profunda da OOP.
Por outro lado, nenhuma ofensa é causada por constantes estáticas, que não constituem um estado significativo e, portanto, são permitidas. Por que não proibir constantes estáticas para obter a máxima consistência com o espírito dependente da instância ? Talvez porque as constantes não precisem ocupar mais memória do que o necessário (se forem forçadas a não-estáticas, serão copiadas para todas as instâncias da classe interna que sejam potencialmente inúteis). Caso contrário, não consigo imaginar o motivo da exceção.
Pode não ser um raciocínio sólido, mas na OMI faz o maior sentido da observação superficial da Oracle sobre o assunto.
fonte
Resposta curta: O modelo mental que muitos programadores têm de como o escopo funciona não é o modelo usado pelo javac. Combinar o modelo mais intuitivo exigiria uma grande mudança na maneira como o javac funciona.
A principal razão pela qual os membros estáticos nas classes internas são desejáveis é a limpeza do código - um membro estático usado apenas por uma classe interna deve viver dentro dele, em vez de ter que ser colocado na classe externa. Considerar:
Considere o que está acontecendo no getID () quando eu uso o identificador não qualificado "outID". O escopo em que esse identificador aparece é semelhante a:
Aqui, novamente, porque é assim que o javac funciona, o nível "Exterior" do escopo inclui membros estáticos e de instância do Exterior. Isso é confuso, porque geralmente nos dizem para pensar na parte estática de uma classe como outro nível do escopo:
Dessa maneira, é claro que staticMethod () pode ver apenas membros estáticos de Outer. Mas se fosse assim que o javac funciona, a referência a uma variável de instância em um método estático resultaria em um erro "o nome não pode ser resolvido". O que realmente acontece é que o nome é encontrado no escopo, mas um nível extra de verificação entra em ação e descobre que o nome foi declarado em um contexto de instância e está sendo referenciado a partir de um contexto estático.
OK, como isso se relaciona com classes internas? Ingenuamente, achamos que não há razão para que as classes internas não possam ter um escopo estático, porque estamos imaginando o escopo funcionando assim:
Em outras palavras, declarações estáticas na classe interna e declarações de instância na classe externa estão no escopo dentro do contexto de instância da classe interna, mas nenhuma delas é realmente aninhada na outra; ambos são aninhados no escopo estático de Outer.
Não é assim que o javac funciona - há um único nível de escopo para membros estáticos e de instância, e o escopo sempre é estritamente ninho. Até a herança é implementada copiando declarações para a subclasse em vez de ramificar e pesquisar no escopo da superclasse.
Para dar suporte a membros estáticos de classes internas, o javac precisaria dividir os escopos estáticos e de instância e oferecer suporte a hierarquias de escopo de ramificação e junção ou estender sua idéia simples de "contexto estático" booleano para mudar para rastrear o tipo de contexto em todos os níveis da classe aninhada no escopo atual.
fonte
Nota: Uma classe aninhada não estática é conhecida como classe interna, portanto você não a possui
non-static inner class
.Uma instância de classe interna não existe sem uma instância correspondente da classe externa. Uma classe interna não pode declarar membros estáticos que não sejam constantes de tempo de compilação. Se fosse permitido, haveria ambiguidade sobre o significado de
static
. Nesse caso, haveria certas confusões:É por isso que os designers provavelmente decidiram não resolver esse problema.
Novamente, você não pode tornar estática uma classe interna, mas pode declarar uma classe estática como aninhada. Nesse caso, essa classe aninhada é realmente parte da classe externa e pode ter membros estáticos sem nenhum problema.
fonte
Este tópico chamou a atenção de muitos, ainda tentarei explicar nos termos mais simples.
Primeiramente, com referência a http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 , uma classe ou interface é inicializada imediatamente antes da primeira ocorrência / invocação de qualquer membro precedido pela palavra-chave estática.
Portanto, se tolerarmos um membro estático dentro de uma classe interna, isso levará à inicialização da classe interna, não necessariamente da classe externa / envolvente. Portanto, dificultamos a sequência de inicialização da classe.
Considere também o fato de que uma classe interna não estática está associada à instância de uma classe envolvente / externa. Portanto, associar-se a uma instância significa que a classe interna existirá dentro de uma instância da classe Outer e será diferente entre as instâncias.
Simplificando o ponto, para acessar o membro estático, precisamos de uma instância de uma classe Exterior, a partir da qual precisaremos novamente criar uma instância de classe interna não estática. Os membros estáticos não devem estar vinculados a instâncias e, portanto, você recebe um erro de compilação.
fonte
Uma classe interna é algo completamente diferente de uma classe aninhada estática, embora ambas sejam similares em sintaxe. As classes aninhadas estáticas são apenas um meio de agrupamento, enquanto as classes internas têm uma forte associação - e acesso a todos os valores de - sua classe externa. Você deve ter certeza de por que deseja usar uma classe interna e, em seguida, deve ficar bem natural qual delas você deve usar. Se você precisar declarar um método estático, provavelmente é uma classe aninhada estática que você deseja.
fonte
Suponha que existam duas instâncias da classe externa e ambas instanciaram a classe interna. Agora, se a classe interna tiver um membro estático, ela manterá apenas uma cópia desse membro na área de heap. Nesse caso, os dois objetos da classe externa se referirão a esse cópia única e eles podem alterá-lo juntos. Isso pode causar a situação "Dirty read", portanto, para impedir que este Java aplique essa restrição. Outro ponto forte para apoiar esse argumento é que o java permite membros estáticos finais aqui, aqueles cujos valores não podem ser alterado de qualquer objeto de classe externa. Por favor, deixe-me se eu estiver errado.
fonte
Antes de tudo, por que alguém deseja definir o membro estático em uma classe interna não estática? A resposta é: para que o membro externo da classe possa usar esses membros estáticos apenas com o nome interno da classe, certo?
Mas, neste caso, podemos definir diretamente o membro na classe externa. que será associado a todos os objetos da classe interna, dentro da instância da classe externa.
como abaixo do código,
pode ser escrito assim
Portanto, na minha opinião, para não complicar o código, o java designer não está permitindo essa funcionalidade ou podemos vê-la em versões futuras com mais alguns recursos.
fonte
Tente tratar a classe como um campo normal, para que você entenda.
fonte
É inútil ter membros da classe interna como estáticos, porque você não poderá acessá-los em primeiro lugar.
Pense nisso: para acessar um membro estático, use className.memberName ,, no nosso caso, deve ser algo como outerclassName.innerclassName.memberName ,,, agora você vê por que a innerclass deve ser estática ....
fonte
Você tem métodos estáticos permitidos em classes aninhadas estáticas. Por exemplo
fonte