Какие правила предписывают наследование статических переменных в Java? - PullRequest
43 голосов
/ 28 марта 2012

У меня есть класс, 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 ]

42 голосов
/ 28 марта 2012

Я не понимаю, почему содержимое 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);
    }
}

Тогда он напечатал бы "bar" четыре раза, потому что первый оператор заставил бы 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 перед его запуском, для пример.

0 голосов
/ 17 марта 2016

Неважно, где вы меняете значение статической переменной, это та же самая переменная 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, чтобы подчеркнуть статическую природу переменной / метода и дать компилятору лучшие возможности для оптимизации.

0 голосов
/ 28 марта 2015

Статические члены не наследуются в Java, так как они являются свойствами класса и загружаются в область класса. они не имели ничего общего с созданием объекта. однако только дочерние классы могут получить доступ к статическим членам своих родительских классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...