Pergunta

Por que não podemos ter método estático em uma classe interna não-estática?

Se eu fizer a estática classe interna funciona. Por quê?

Foi útil?

Solução

Como um exemplo de uma classe interna está implicitamente associado com um exemplo da sua classe externa, não pode definir quaisquer métodos estáticos em si. Desde uma classe aninhada estática não pode se referir diretamente a variáveis ??de instância ou métodos definidos em sua classe delimitador, ele pode usá-los apenas através de uma referência de objeto, é seguro para declarar métodos estáticos em uma classe aninhada estática.

Outras dicas

Não há muito ponto de permitir que um método estático em uma classe interna não-estática; como você acessá-lo? Você não pode acessar (pelo menos inicialmente) uma instância de classe interna não-estática, sem passar por uma instância da classe externa. Não há puramente forma estática de se criar uma classe interna não-estático.

Para uma Outer classe externa, você pode acessar um método test() estática assim:

Outer.test();

Para uma Inner classe interna estática, você pode acessar seu método innerTest() estática assim:

Outer.Inner.innerTest();

No entanto, se Inner não é estático, não há agora nenhuma puramente forma estática para referenciar o innertest método. classes internas não-estáticos estão vinculados a uma instância específica de sua classe externa. A função é diferente de uma constante, em que uma referência a Outer.Inner.CONSTANT é garantido para ser inequívocos de uma forma que um Outer.Inner.staticFunction(); chamada de função não é. Vamos dizer que você tem Inner.staticFunction() que chama getState(), que é definido em Outer. Se você tentar invocar essa função estática, agora você tem uma referência ambígua para a classe interna. Ou seja, em qual instância da classe interna você chamar a função estática? Importa. Veja, não há nenhuma maneira verdadeiramente estática para referência que o método estático, devido à referência implícita ao objeto externo.

Paul Bellora é correto que os projetistas da linguagem poderia ter permitido isso. Teriam então cuidadosamente para não permitir qualquer acesso à referência implícita para o exterior na classe métodos estáticos da classe interna não estático. Neste ponto, o que é o valor a este ser uma classe interna se você não pode fazer referência a classe externa, exceto estaticamente? E se o acesso estática é bom, então por que não declarar toda a estática classe interna? Se você simplesmente fazer a classe interna-se estático, então você não tem referência implícita à classe externa, e você já não tem essa ambiguidade.

Se você realmente necessidade métodos estáticos em uma classe interna não-estático, então provavelmente você precisa repensar o seu design.

Eu tenho uma teoria, que pode ou não pode estar correto.

Primeiro, você deve saber algumas coisas sobre como classes internas são implementados em Java. Suponha que você tem essa classe:

class Outer {
    private int foo = 0;
    class Inner implements Runnable {
        public void run(){ foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(); }
}

Quando você compilá-lo, o bytecode gerado vai olhar como se você escreveu algo como isto:

class Outer {
    private int foo = 0;
    static class Inner implements Runnable {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public void run(){ this$0.foo++; }
    }
    public Runnable newFooIncrementer(){ return new Inner(this); }
}

Agora, se nós não permitir métodos estáticos em classes internas não-estáticos, você pode querer fazer algo como isto.

class Outer {
    private int foo = 0;
    class Inner {
        public static void incrFoo(){ foo++; }
    }
}

... que parece bastante razoável, como a classe Inner parece ter uma encarnação por exemplo Outer. Mas, como vimos acima, as classes internas não-estáticos são realmente apenas açúcar sintático para estáticos classes "internos", de modo que o último exemplo seria aproximadamente equivalente a:

class Outer {
    private int foo = 0;
    static class Inner {
        private final Outer this$0;
        public Inner(Outer outer){
            this$0 = outer;
        }
        public static void incrFoo(){ this$0.foo++; }
    }
}

... que claramente não vai funcionar, desde this$0 não é estática. Este tipo de explica por que métodos estáticos não são permitidos (embora você poderia fazer o argumento que você poderia permitir métodos estáticos, desde que eles não fazem referência ao objeto delimitador), e por que você não pode ter campos estáticos não-finais ( seria um contra-senso, se as instâncias de classes internas não-estáticos de diferentes objetos compartilhados "estado estático"). Ele também explica por que os campos finais são permitido (desde que eles não fazer referência ao objeto anexando).

A única razão pela qual "não é uma obrigação", então por que se preocupar para apoiá-lo?

Sintaticamente, não há nenhuma razão para proibir uma classe interna de ter membros estáticos. Embora uma instância de Inner está associada a uma instância de Outer, ainda é possível usar Outer.Inner.myStatic para se referir um membro estático de Inner se java decidir fazê-lo.

Se você precisa de algo share entre todos os casos de Inner, você pode simplesmente colocá-los em Outer como membros estáticos. Esta não é pior do que você usar membros estáticos em Inner, onde Outer ainda pode acessar qualquer membro particular de Inner qualquer maneira (não melhora encapsulamento).

Se você precisa de algo share entre todas as instâncias de Inner criado por um objeto outer, faz mais sentido para colocá-los em classe Outer como membros comuns.

Eu não concordo a opinião de que "uma classe aninhada estática é praticamente apenas uma classe de nível superior". Eu acho que é melhor para realmente considerar uma classe aninhada / classe interna estática, como uma parte da classe externa, porque eles podem acessar membros privados da classe externa. E membros da classe externa são "membros da classe interna", bem. Portanto, não há necessidade de apoiar membro estático na classe interna. Um membro comum / static em classe externa será suficiente.

resposta curta: O modelo mental a maioria dos programadores têm de como escopo funciona não é o modelo usado por javac. Combinando o modelo mais intuitivo teria exigido uma grande mudança de como funciona o javac.

A principal razão que os membros estáticos em classes internas são desejáveis ??é para limpeza de código - um membro estático utilizado apenas por uma classe interna deve viver dentro dele, ao invés de ter que ser colocado na classe externa. Considere o seguinte:

class Outer {
   int outID;

   class Inner {
      static int nextID;
      int id = nextID++;

      String getID() {
         return outID + ":" + id;
      }
   }
}

Considere o que está acontecendo em getID () quando eu uso o identificador não qualificado "outID". O escopo no qual este identificador aparece é algo como:

Outer -> Inner -> getID()

Aqui, novamente, porque isto é apenas como javac funciona, o nível de "Outer" do escopo inclui tanto estática e membros de instância de Outer. Esta é confuso porque geralmente são orientados a pensar na parte estática de uma classe como um outro nível do escopo:

Outer static -> Outer instance -> instanceMethod()
         \----> staticMethod()

Nesta maneira de pensar sobre isso, é claro staticMethod () só pode ver os membros estáticos de Outer. Mas se isso fosse como funciona o javac, então fazer referência a uma variável de instância em um método estático resultaria em um "nome não pode ser resolvido" erro. O que realmente acontece é que o nome é encontrada em escopo, mas, em seguida, um nível extra de verificação nos chutes e descobre que o nome foi declarado num contexto instância e está sendo referenciados a partir de um contexto estático.

OK, como isso se relaciona com classes internas? Ingenuamente, pensamos que não há nenhuma razão classes internas não pode ter um escopo estático, porque estamos imaginando o escopo de trabalho como este:

Outer static -> Outer instance -> Inner instance -> getID()
         \------ Inner static ------^

Em outras palavras, declarações estáticos nas declarações de classe e instância interna da classe exterior são ambos em escopo dentro do contexto instância da classe interna, mas nenhum deles é realmente aninhado em outro; ambos são em vez aninhada no âmbito estática de Outer.

Isso não é apenas como funciona o javac - há um único nível de espaço para ambos os membros estáticos e de instância e de escopo sempre estritamente ninhos. herança ainda é implementado copiando declarações para a subclasse em vez de ramificação e pesquisar o escopo superclasse.

Para apoiar os membros estáticos de classes internas javac teria que quer estática dividida e exemplo escopos e apoio ramificação e reunir hierarquias de escopo, ou ele teria que estender sua boolean simples "estático contexto" idéia mudar para acompanhar o tipo de contexto em todos os níveis de classe aninhada no escopo atual.

Por que não podemos ter método estático em uma classe interna não-estática?

Nota:. A classe aninhada não-estático é conhecida como classe interna para que você não tem non-static inner class como tal

Um exemplo classe interna não tem existência sem um exemplo correspondente da classe externa. Uma classe interna não pode declarar que não sejam constantes de tempo de compilação membros estáticos. Se fosse permitido, então não teria sido ambigüidade sobre o que significa de static. Nesse caso, teria havido certas confusões:

  1. Será que isso significa que há apenas uma instância de VM?
  2. Ou apenas uma instância por objeto externo?

É por isso que os designers provavelmente tomou a decisão de não lidar com este problema em tudo.

Se eu fizer a estática classe interna funciona. Por quê?

Mais uma vez você não pode fazer uma classe estática interior em vez você pode declarar uma classe estática como aninhada. Nesse caso, isso classe aninhada é realmente parte da classe externa e pode ter membros estáticos, sem qualquer problema.

Este tópico tem a atenção obtida a partir de muitos, ainda vou tentar explicar da forma mais simples dos termos.

Em primeiro lugar, com referência a http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 , uma classe ou interface é inicializado imediatamente antes da primeira ocorrência / invocação de qualquer membro que é precedido pela palavra-chave estática.

  1. Assim, se nós colocar-se com um membro estático dentro de uma classe interna, conduzirá à inicialização da classe interna, não necessariamente o exterior / classe delimitador. Então, nós dificultar a seqüência de inicialização de classe.

  2. Também considerar o fato de que uma classe interna não-estático está associada com o exemplo de uma classe envolvente / exterior. Assim, associando com uma instância será dizer, que a classe interna existirá dentro de uma instância da classe externa e serão diferentes entre casos.

Simplificar o ponto, a fim de acessar o membro estático precisamos de uma instância de uma classe externa, a partir do qual vamos novamente precisa criar uma instância da classe interna não-estática. Membros estáticos não devem ser obrigados a instâncias e, portanto, você recebe um erro de compilação.

De: https://docs.oracle.com/javase /tutorial/java/javaOO/nested.html

Tal como com os métodos de instância e variáveis, uma classe interna está associada com um exemplo da sua classe envolvente e tem acesso directo aos métodos e campos que do objecto. Além disso, como uma classe interna está associada a uma instância, não pode definir quaisquer-se membros estáticos.

explicação da Oracle é superficial e handwavy. Uma vez que não há nenhuma razão técnica ou sintática para membros estáticos antecipar dentro de uma classe interna (é permitido em outras linguagens como C #) motivação dos designers de Java foi sabor provável conceitual e / ou uma questão de conveniência técnica.

Aqui está a minha especulação:

classes de nível superior Ao contrário, classes internas são dependentes de exemplo: uma instância da classe interna está associada com uma ocorrência de cada uma das suas classes exteriores e tem acesso directo aos seus membros. Esta é a principal motivação para tê-los em Java. Expressa de outra forma: uma classe interna é significou para instanciação no contexto de uma instância da classe externa. Sem uma instância da classe externa, uma classe interna não deve ser mais utilizável do que os outros membros da instância da classe externa. Vamos nos referir a isso como o espírito dependente da instância de classes internas.

A própria natureza dos membros estáticos (que não são orientada a objetos) confrontos com o instância dependente espírito de classes internas (que é orientada a objetos) porque você pode fazer referência / chamar um membro estático de uma classe interna sem uma instância da classe externa usando o nome de classe interna qualificado.

As variáveis ??estáticas em particular, podem tropeçar em outra forma: duas instâncias de uma classe interna que estão associados com diferentes instâncias da classe externa iria partilhar variáveis ??estáticas. Desde variáveis ??são um componente do estado, as duas instâncias de classe internas seria, com efeito, estado share independentemente das instâncias de classe exteriores que estão associados. Não é que é inaceitável que variáveis ??estáticas trabalhar desta forma (que aceitá-los em Java como um compromisso razoável para a pureza OOP), mas há sem dúvida uma ofensa mais profunda tinha de ser, permitindo-lhes em classes internas cujos casos já são acoplados com instâncias de classe exteriores por design. Proibindo membros estáticos dentro de classes internas em favor da espírito dependente da instância colhe a vantagem adicional de equacionar esta ofensa OOP mais profunda.

Por outro lado, existe tal delito é acarretada por constantes estáticas, que não significativamente constituem Estado e assim que estes são permitidas. Por que não proíbem constantes estáticas para o máximo de coerência com o espírito dependente da instância ? Talvez porque constantes necessidade não ocupam mais memória do que o necessário (se eles são forçados a ser não-estático, então eles estão copiados para cada instância da classe interna que é potencialmente um desperdício). Caso contrário, eu não posso imaginar o motivo da exceção.

Pode não ser o raciocínio rock-solid mas IMO faz mais senso de observação superficial da Oracle sobre o assunto.

Uma classe interna é algo completamente diferente de uma classe aninhada estática apesar de ambos são semelhantes em sintaxe. classes aninhadas estáticas são apenas um meio para agrupar enquanto classes internas têm uma forte associação - e acesso a todos os valores de - sua classe externa. Você deve ter certeza por que você quer usar uma classe interna e, em seguida, ele deve vir muito natural que aquele que você tem que usar. Se você precisa declarar um método estático é provavelmente uma classe aninhada estática que você quer de qualquer maneira.

suponho que há duas instâncias de classe externa e ambos têm instanciado class.Now interior se classe interna tem um membro estático, então ele irá manter apenas uma cópia desse membro na pilha area.In neste caso ambos os objetos da classe externa vai referem-se a esta única cópia e eles podem alterá-lo together.This pode causar "Dirty ler" a situação, portanto, para evitar que esse Java aplicou este ponto forte restriction.Another para apoiar este argumento é que java permite que os membros estáticos finais aqui, aqueles cujos valores podem 't ser alterado a partir de qualquer objeto de classe externa. Por favor, deixe-me se eu estiver errado.

Antes de tudo por que alguém deseja definir o membro estático em uma classe non-static interior? resposta é, de modo que o membro da classe externa pode usar aqueles membro estático com o nome da classe interior só, certo?

Mas para este caso podemos definir diretamente o membro na classe externa. que vai ser associado com todos os objectos de classe interna, dentro da instância de classe externa.

como o código abaixo,

public class Outer {

  class Inner {

    public static void method() {

    }

  }

}

pode ser escrita como esta

public class Outer {

  void method() {

   }

   class Inner {


  }

}

Assim, em minha opinião não complicar o designer java de código não está permitindo que essa funcionalidade ou podemos ver esta funcionalidade em futuras versões com mais alguns recursos.

Tente tratar a classe como um campo normal, então você vai entender.

//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something 

É inútil que os alunos internos como estática, porque você não será capaz de acessá-los em primeiro lugar.

Pense sobre isso, para acessar um membro estático você usa className.memberName ,, em nosso caso, deve ser algo como outerclassName.innerclassName.memberName ,,, agora você vê porque innerclass deve ser estático ....

Você está autorizado métodos estáticos em classes aninhadas estáticas. Por exemplo

public class Outer {

  public static class Inner {

    public static void method() {

    }
  }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top