¿Cuáles son las reglas que dictan la herencia de variables estáticas en Java?

Tengo una clase, Super :

 public class Super { public static String foo = "foo"; } 

También tengo otra clase, Sub que se extiende Super :

 public class Sub extends Super { static { foo = "bar"; } public static void main (String[] args) { System.out.println(Super.foo); } } 

Cuando lo ejecuto, imprime la bar .
Mi tercera (y última) clase es Testing :

 public class Testing { public static void main (String[] args) { System.out.println(Super.foo); System.out.println(Sub.foo); System.out.println(Super.foo); } } 

Esto imprime:

 foo foo foo 

No entiendo por qué los contenidos de foo varían dependiendo de a qué clase lo accedas. ¿Alguien puede explicar?

No entiendo por qué los contenidos de foo varían dependiendo de a qué clase lo accedas.

Básicamente es una cuestión de inicialización de tipo. El valor de foo se establece en "bar" cuando Sub se inicializa. Sin embargo, en su clase de Testing , la referencia a Sub.foo se comstack en realidad en una referencia a Super.foo , por lo que no termina inicializando Sub , por lo que foo nunca se convierte en "bar" .

Si cambia su código de Prueba a:

 public class Testing { public static void main (String[] args) { Sub.main(args); System.out.println(Super.foo); System.out.println(Sub.foo); System.out.println(Super.foo); } } 

Luego imprimía “barra” cuatro veces, porque la primera statement Sub a Sub a inicializarse, lo que cambiaría el valor de foo . No se trata de dónde se accede en absoluto.

Tenga en cuenta que esto no se trata solo de la carga de clase, se trata de la inicialización de clase. Las clases se pueden cargar sin inicializar. Por ejemplo:

 public class Testing { public static void main (String[] args) { System.out.println(Super.foo); System.out.println(Sub.class); System.out.println(Super.foo); } } 

Eso todavía imprime “foo” dos veces, mostrando que Sub no se inicializa, pero definitivamente está cargado , y el progtwig fallará si elimina el archivo Sub.class antes de ejecutarlo, por ejemplo.

No importa dónde cambie el valor de una variable estática, es la misma variabile foo, en Sub o Super . Tampoco importa cuántos new Super new Sub o new Super crees y luego modifiques. El cambio se verá en todas partes, ya que Super.foo , Sub.foo , obj.foo comparten el mismo Super.foo Sub.foo . obj.foo también funciona con los tipos primitivos:

 class StaticVariable{ public static void main(String[] args){ System.out.println("StaticParent.a = " + StaticParent.a);// a = 2 System.out.println("StaticChild.a = " + StaticChild.a);// a = 2 StaticParent sp = new StaticParent(); System.out.println("StaticParent sp = new StaticParent(); sp.a = " + sp.a);// a = 2 StaticChild sc = new StaticChild(); System.out.println(sc.a);// a = 5 System.out.println(sp.a);// a = 5 System.out.println(StaticParent.a);// a = 5 System.out.println(StaticChild.a);// a = 5 sp.increment();//result would be the same if we use StaticParent.increment(); or StaticChild.increment(); System.out.println(sp.a);// a = 6 System.out.println(sc.a);// a = 6 System.out.println(StaticParent.a);// a = 6 System.out.println(StaticChild.a);// a = 6 sc.increment(); System.out.println(sc.a);// a = 7 System.out.println(sp.a);// a = 7 System.out.println(StaticParent.a);// a = 7 System.out.println(StaticChild.a);// a = 7 } } class StaticParent{ static int a = 2; static void increment(){ a++; } } class StaticChild extends StaticParent{ static { a = 5;} } 

Puede hacer referencia a una variable / método estático a través de un objeto (como sc.a ) o mediante su nombre de clase (como StaticParent.a ). Es preferible usar ClassName.staticVariable para enfatizar la naturaleza estática de la variable / método y para dar al comstackdor mejores oportunidades para la optimización.

Los miembros estáticos no se heredan en Java ya que son las propiedades de la clase y se cargan en el área de clase. no tenían nada que ver con la creación de objetos. sin embargo, solo las clases secundarias pueden acceder a los miembros estáticos de sus clases principales.