Какие правила предписывают наследование статических переменных в 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, так как они являются свойствами класса и загружаются в область класса. они не имели ничего общего с созданием объекта. однако только дочерние классы могут получить доступ к статическим членам своих родительских классов.

Другие вопросы по тегам