usar son restricción qué métodos método metodos metodo los llamar instancia estáticos estatico estatica ejemplos ejemplo crear como clases clase atributos java class static inner-classes

java - restricción - qué son los atributos de clase estáticos



¿Por qué no podemos tener un método estático en una clase interna(no estática)? (13)

¿Por qué no podemos tener un método estático en una clase interna no estática?

Si hago que la clase interna estética, funciona. Por qué ?


¿Por qué no podemos tener un método estático en una clase interna no estática?

Nota: Una clase anidada no estática se conoce como clase interna por lo que no tiene non-static inner class como tal.

Una instancia de clase interna no tiene existencia sin una instancia correspondiente de clase externa. Una clase interna no puede declarar miembros estáticos que no sean constantes de tiempo de compilación. Si se permitiera, habría habido ambigüedad sobre el significado de la static . En ese caso habría habido ciertas confusiones:

  1. ¿Significa que solo hay una instancia en VM?
  2. ¿O solo una instancia por objeto externo?

Es por eso que los diseñadores probablemente tomaron la decisión de no manejar este problema en absoluto.

Si hago que la clase interna estética, funciona. Por qué ?

De nuevo, no puede hacer que una clase interna sea estática, sino que puede declarar una clase estática como anidada. En ese caso, esta clase anidada es en realidad parte de la clase externa y puede tener miembros estáticos sin ningún problema.


Debido a que una instancia de una clase interna está asociada implícitamente con una instancia de su clase externa, no puede definir ningún método estático en sí mismo. Como una clase anidada estática no puede hacer referencia directamente a variables de instancia o métodos definidos en su clase adjunta, solo puede usarlos a través de una referencia de objeto, es seguro declarar métodos estáticos en una clase anidada estática.


En primer lugar, ¿por qué alguien quiere definir el miembro estático en una clase interna no estática? La respuesta es, para que el miembro de la clase externa pueda usar esos miembros estáticos solo con el nombre de la clase interna, ¿verdad?

Pero para este caso, podemos definir directamente al miembro en la clase externa. que se asociará con todos los objetos de la clase interna, dentro de la instancia de clase externa.

como el código de abajo,

public class Outer { class Inner { public static void method() { } } }

puede escribirse así

public class Outer { void method() { } class Inner { } }

Entonces, en mi opinión, no complicar el código. El diseñador de Java no permite esta funcionalidad o podemos ver esta funcionalidad en versiones futuras con algunas características adicionales.


Es inútil que los miembros de la clase interna estén estáticos porque, en primer lugar, no podrás acceder a ellos.

Piensa en esto, para acceder a un miembro estático usas className.memberName ,, en nuestro caso, debería ser algo así como outerclassName.innerclassName.memberName ,,, ahora ves por qué innerclass debe ser estático ....


Este tema ha atraído la atención de muchos, aún intentaré explicarlo en los términos más simples.

En primer lugar, con referencia a http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 , una clase o interfaz se inicializa inmediatamente antes de la primera ocurrencia / invocación de cualquier miembro que esté precedido por la palabra clave estática.

  1. Entonces, si soportamos un miembro estático dentro de una clase interna, conducirá a la inicialización de la clase interna, no necesariamente a la clase externa / circundante. Por lo tanto, obstaculizamos la secuencia de inicialización de clase.

  2. También considere el hecho de que una clase interna no estática está asociada con la instancia de una clase envolvente / externa. Entonces, asociarse con una instancia significará que la clase interna existirá dentro de una instancia de clase externa y será diferente entre las instancias.

Simplificando el punto, para acceder al miembro estático necesitamos una instancia de una clase Externa, desde la cual nuevamente necesitaremos crear una instancia de clase interna no estática. No se supone que los miembros estáticos estén vinculados a instancias y, por lo tanto, recibes un error de compilación.


La única razón es "no es obligatorio", ¿por qué molestarse en apoyarlo?

Sintácticamente, no hay ninguna razón para prohibir que una clase interna tenga miembros estáticos. Aunque una instancia de Inner está asociada con una instancia de Outer , aún es posible usar Outer.Inner.myStatic para referir un miembro estático de Inner si java decide hacerlo.

Si necesita compartir algo entre todas las instancias de Inner , puede simplemente ponerlas en Outer como miembros estáticos. Esto no es peor que el uso de miembros estáticos en Inner , donde Outer aún puede acceder a cualquier miembro privado de Inner todos modos (no mejora la encapsulación).

Si necesita compartir algo entre todas las instancias de Inner creado por un objeto outer , tiene más sentido colocarlas en la clase Outer como miembros ordinarios.

No estoy de acuerdo con la opinión de que "una clase anidada estática es prácticamente una clase de nivel superior". Creo que es mejor considerar realmente una clase / clase interna anidada estática como parte de la clase externa, ya que pueden acceder a los miembros privados de la clase externa. Y los miembros de la clase externa también son "miembros de la clase interna". Entonces no hay necesidad de soportar miembros estáticos en la clase interna. Un miembro ordinario / estático en la clase externa será suficiente.


No tiene mucho sentido permitir un método estático en una clase interna no estática; ¿cómo lo accederías? No puede acceder (al menos inicialmente) a una instancia de clase interna no estática sin pasar por una instancia de clase externa. No hay una forma puramente estática de crear una clase interna no estática.

Para una clase externa Outer , puede acceder a una test() método estático test() como esta:

Outer.test();

Para una clase interna estática interna, puede acceder a su método estático innerTest() esta manera:

Outer.Inner.innerTest();

Sin embargo, si Inner no es estático, ahora no hay una forma puramente estática de referenciar el método más innertest . Las clases internas no estáticas están ligadas a una instancia específica de su clase externa. Una función es diferente de una constante, en el sentido de que se garantiza que una referencia a Outer.Inner.CONSTANT es ambigua de forma que una función llame a Outer.Inner.staticFunction(); no es. Digamos que tiene Inner.staticFunction() que llama a getState() , que está definido en Outer . Si intenta invocar esa función estática, ahora tiene una referencia ambigua a la clase interna. Es decir, ¿en qué instancia de la clase interna invocas la función estática? Importa. Ver, no hay una manera verdaderamente estática de referenciar ese método estático, debido a la referencia implícita al objeto externo.

Paul Bellora tiene razón en que los diseñadores del lenguaje podrían haberlo permitido. Tendrían que rechazar cuidadosamente cualquier acceso a la referencia implícita a la clase externa en métodos estáticos de la clase interna no estática. En este punto, ¿cuál es el valor de que esto sea una clase interna si no puede hacer referencia a la clase externa, excepto estáticamente? Y si el acceso estático está bien, entonces ¿por qué no declarar toda la clase interna estática? Si simplemente hace que la clase interna en sí misma sea estática, entonces no tiene ninguna referencia implícita a la clase externa, y ya no tiene esta ambigüedad.

Si realmente necesitas métodos estáticos en una clase interna no estática, entonces probablemente necesites replantear tu diseño.


Respuesta corta: El modelo mental que la mayoría de los programadores tienen de cómo funciona el alcance no es el modelo utilizado por javac. Coincidir con el modelo más intuitivo habría requerido un gran cambio en cómo funciona javac.

La razón principal por la que los miembros estáticos en las clases internas son deseables es por la limpieza del código: un miembro estático utilizado solo por una clase interna debería vivir dentro de él, en lugar de tener que ubicarse en la clase externa. Considerar:

class Outer { int outID; class Inner { static int nextID; int id = nextID++; String getID() { return outID + ":" + id; } } }

Considere lo que está pasando en getID () cuando uso el identificador no calificado "outID". El alcance en el que aparece este identificador parece algo así como:

Outer -> Inner -> getID()

Aquí, una vez más, porque así es como funciona javac, el nivel "Externo" del alcance incluye tanto miembros estáticos como de instancia de Outer. Esto es confuso porque generalmente se nos dice que pensemos en la parte estática de una clase como otro nivel del alcance:

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

En esta forma de pensar, por supuesto staticMethod () solo puede ver miembros estáticos de Outer. Pero si fuera así como funciona javac, hacer referencia a una variable de instancia en un método estático daría como resultado un error de "nombre no se puede resolver". Lo que realmente sucede es que el nombre se encuentra en el alcance, pero luego aparece un nivel extra de verificación y se da cuenta de que el nombre fue declarado en un contexto de instancia y se está haciendo referencia a partir de un contexto estático.

OK, ¿cómo se relaciona esto con las clases internas? Ingenuamente, creemos que no hay razón para que las clases internas no puedan tener un alcance estático, porque estamos imaginando el alcance trabajando así:

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

En otras palabras, las declaraciones estáticas en la clase interna y las declaraciones de instancia en la clase externa están dentro del contexto de la instancia de la clase interna, pero ninguna de ellas está realmente anidada en la otra; ambos están anidados en el ámbito estático de Outer.

Así no es cómo funciona javac: hay un único nivel de alcance para los miembros estáticos y de instancia, y el alcance siempre anida estrictamente. Incluso la herencia se implementa copiando declaraciones en la subclase en lugar de ramificar y buscar el alcance de la superclase.

Para soportar miembros estáticos de clases internas, javac tendría que dividir los ámbitos estáticos y de instancia y permitir la ramificación y volver a unir las jerarquías de ámbito, o debería ampliar su idea booleana de "contexto estático" para cambiar el tipo de contexto en todos los niveles de clase anidada en el alcance actual.


Se permiten métodos estáticos en clases anidadas estáticas. Por ejemplo

public class Outer { public static class Inner { public static void method() { } } }


Supongamos que hay dos instancias de clase externa y ambas tienen una instancia de clase interna. Ahora bien, si la clase interna tiene un miembro estático, guardará solo una copia de ese miembro en el área de montón. En este caso, ambos objetos de la clase externa se referirán a este copia única y pueden alterarlo juntos. Esto puede causar una situación de "lectura sucia", por lo tanto, para evitar que Java aplique esta restricción. Otro punto fuerte para apoyar este argumento es que java permite miembros estáticos finales aquí, aquellos cuyos valores no pueden ser cambiado desde cualquiera de los objetos de la clase externa. Por favor, déjame si estoy equivocado.


Tengo una teoría, que puede o no ser correcta.

En primer lugar, debe saber algunas cosas sobre cómo se implementan las clases internas en Java. Supongamos que tienes esta clase:

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

Cuando lo compila, el bytecode generado parecerá que escribió algo como esto:

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); } }

Ahora, si permitimos métodos estáticos en clases internas no estáticas, es posible que desee hacer algo como esto.

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

... que parece bastante razonable, ya que la clase Inner parece tener una encarnación por instancia Outer . Pero como vimos anteriormente, las clases internas no estáticas realmente son solo azúcar sintáctico para clases "internas" estáticas, por lo que el último ejemplo sería 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 no funcionará, ya que this$0 no es estático. Este tipo de explicación explica por qué los métodos estáticos no están permitidos (aunque podría argumentar que podría permitir métodos estáticos siempre que no hicieran referencia al objeto adjunto) y por qué no puede tener campos estáticos no finales ( sería contrario a la intuición si las instancias de clases internas no estáticas de diferentes objetos compartieran "estado estático"). También explica por qué los campos finales están permitidos (siempre que no hagan referencia al objeto adjunto).


Trata de tratar la clase como un campo normal, entonces lo entenderás.

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


Una clase interna es algo completamente diferente de una clase anidada estática aunque ambas son similares en sintaxis. Las clases anidadas estáticas son solo un medio para agrupar, mientras que las clases internas tienen una fuerte asociación y acceso a todos los valores de su clase externa. Debe estar seguro de por qué quiere usar una clase interna y luego debería ser bastante natural cuál debe usar. Si necesita declarar un método estático, probablemente sea una clase anidada estática que desee de todos modos.