Какие правила предписывают наследование статических переменных в Java?
У меня есть класс, Super
:
public class Super {
public static String foo = "foo";
}
У меня также есть другой класс, Sub
это расширяет Super
:
public class Sub extends Super {
static {
foo = "bar";
}
public static void main (String[] args) {
System.out.println(Super.foo);
}
}
Когда я запускаю его, он печатает bar
,
Мой третий (и последний) класс 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);
}
}
Это печатает:
foo
foo
foo
Я не понимаю, почему содержание foo
варьироваться в зависимости от того, из какого класса вы получаете к нему доступ. Кто-нибудь может объяснить?
3 ответа
Я не понимаю, почему содержимое foo зависит от того, из какого класса вы к нему обращаетесь.
В основном это вопрос инициализации типа. Значение foo
установлен в "bar"
когда Sub
инициализируется. Однако в вашем Testing
класс, ссылка на Sub.foo
на самом деле компилируется в ссылку на Super.foo
, так что это не заканчивается инициализация Sub
, так foo
никогда не становится "bar"
,
Если вы измените код тестирования на:
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);
}
}
Тогда он напечатал бы "бар" четыре раза, потому что первое утверждение заставит Sub
быть инициализированным, что изменит значение foo
, Это не вопрос, откуда к нему обращаются вообще.
Обратите внимание, что речь идет не только о загрузке классов, но и об инициализации классов. Классы могут быть загружены без инициализации. Например:
public class Testing {
public static void main (String[] args) {
System.out.println(Super.foo);
System.out.println(Sub.class);
System.out.println(Super.foo);
}
}
Это все еще печатает "Foo" дважды, показывая, что Sub
не инициализирован - но он определенно загружен, и программа завершится ошибкой, если вы удалите Sub.class
файл перед запуском, например.
Неважно, где вы изменяете значение статической переменной, это та же переменная foo, в Sub
или же Super
, Неважно, сколько new Sub
или же new Super
объекты, которые вы создаете, а затем изменяете. Изменение будет видно везде, так как Super.foo
, Sub.foo
, obj.foo
совместно использовать тот же кусок памяти. Это работает и с примитивными типами:
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;}
}
Вы можете ссылаться на статическую переменную / метод через объект (например, sc.a
) или через имя класса (например, StaticParent.a
). Предпочтительно использовать ClassName.staticVariable
подчеркнуть статическую природу переменной / метода и предоставить компилятору лучшие возможности для оптимизации.
Статические члены не наследуются в Java, так как они являются свойствами класса и загружаются в область класса. они не имели ничего общего с созданием объекта. однако только дочерние классы могут получить доступ к статическим членам своих родительских классов.