Поздняя привязка? Поле против свойства. Self vs Static

Это беспокоило меня в течение долгого времени, поэтому я подумал, что буду идти дальше и спрашивать.

Если я напишу

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

            public void printName()
            {
                    System.out.println( name() );
            }

            public String name()
            {
                    return name;
            }
    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";

            public String name()
            {
                    return name;
            }
    }
}

то выход

shape
triangle

But Если я напишу

import java.util.*;
import java.lang.*;

class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
            new Shape();
            new Triangle();
    }

    public static class Shape
    {
            static String name = "shape";

            Shape()
            {
                    printName();
            }

            public void printName()
            {
                    System.out.println( name );
            }

    }

    public static class Triangle extends Shape
    {
            static String name = "triangle";
    }
}

то выход

shape
shape

В первой версии мне приходится копировать и вставлять одну и ту же функцию getName() снова и снова в каждый подкласс. Там должен быть лучший способ. Что мне нужно изменить во втором примере?

3

6 ответы

статические поля недоступны из родительских классов. Класс Shape не «видит» статическое поле name класса Triangle и использует свое собственное статическое поле name .

UPD: You ask: what you need to change in second example? More specifically, your first example is correct "fixing" of your second example. The only correct way is using some getter method like your name() method.

UPD2: (from my commentary): Well, another way: forgive about any kind of field name. Use instead method called name() (not static!) which will return in each class needed name. Just return "shape"; or return "triangle" in them;

5
добавлено
@beardedlinuxgeek, если вы хотите сохранить статический характер поля name , ваш может, например, переопределить метод printName() . Но я не думаю, что это лучший способ. Что касается меня, на практике в таких ситуациях я всегда создаю некоторый getter для таких статических полей.
добавлено автор Andremoniy, источник
Конечно, вы получите тот же результат! Поскольку родительский класс Shape использует ссылку на статическое поле name в printName .
добавлено автор Andremoniy, источник
Ну, еще один способ: простить о любом виде поля name . Используйте вместо этого метод, называемый name() (не статический!), Который будет возвращать в каждом классе необходимое имя. Просто return "shape"; или return "triangle";
добавлено автор Andremoniy, источник
См. Мой второй ответ. Это еще один (но забавный) способ.
добавлено автор Andremoniy, источник
Поэтому мне нужно скопировать «public String name() {return name;}» в каждый отдельный подкласс? Конечно, есть лучший способ.
добавлено автор beardedlinuxgeek, источник
Игнорируйте тот факт, что это статическое свойство. Если вы измените «статическое имя строки» на «String name», вы получите тот же результат.
добавлено автор beardedlinuxgeek, источник
Я знаю, что в PHP вы можете написать «static:» вместо «self:», чтобы делать то, о чем я говорю ( php.net/manual/en/language.oop5.late-static-bindings.php ). Я все еще не могу поверить, что мне нужно копировать/вставлять одну и ту же функцию во все подклассы ... но я думаю, что я могу жить.
добавлено автор beardedlinuxgeek, источник
Всякий раз, когда вы ссылаетесь на статическое поле, вы статически привязываетесь к этому конкретному полю. Статические поля не преувеличиваются с наследованием, поэтому вы получаете два разных поля имени (один в форме, один в треугольнике). Метод name() Shape статически привязан к полю Shape.name, а тот, который находится в треугольнике, статически привязан к полю Triangle.name. Полиморфизма там нет
добавлено автор Claudio, источник

Ну, я уже ответил на этот вопрос отрицательным ключом. Но как своего рода шутка и смешное решение (, которое будет работать !!! ), вы можете изменить свой метод printName() на этот:

public void printName() throws NoSuchFieldException, IllegalAccessException {
    System.out.println((String)(this.getClass().getDeclaredField("name").get(this)));
}

Это только одно изменение, которое вы должны сделать в примере второй для получения вывода

shape
triangle
1
добавлено

Ну, я уже ответил на этот вопрос отрицательным ключом. Но как своего рода шутка и смешное решение (, которое будет работать !!! ), вы можете изменить свой метод printName() на этот:

public void printName() throws NoSuchFieldException, IllegalAccessException {
    System.out.println((String)(this.getClass().getDeclaredField("name").get(this)));
}

Это только одно изменение, которое вы должны сделать в примере второй для получения вывода

shape
triangle
1
добавлено

Это отличная иллюстрация того, как Java разрешает имена для значений. У вас есть две переменные, называемые name , одна в Shape и одна в Triangle . Даже если Triangle является подклассом Shape , это полностью несвязанные переменные . Это потому, что они статичны; статические вещи никогда не переопределяются, потому что они принадлежат классу, а не объекту. В Shape , когда вы ссылаетесь на name , это действительно сокращение для Shape.name . Аналогично, в Triangle , name означает Triangle.name . тот же символ относится к различным переменным в разных областях .

В этом коде:

public class Shape {
    static String name = "shape";

    public static void main(String[] args) {
        System.out.println(name);
    }
}

class Colour {
    static String name = "colour";
}

Вы бы не подумали, что выход будет «цветным», не так ли? Это именно та ситуация в коде, который вы показываете. Наследование отношений между двумя классами - просто красная селедка.

Если вы хотите, чтобы имя было полиморфным, ваш единственный вариант - использовать метод экземпляра, потому что методы экземпляра - это единственные вещи, которые могут быть полиморфными. Самый сжатый способ сделать это - включить константы в методы:

class Main {

    public static void main(String[] args) {
        new Shape();
        new Triangle();
    }

    public static class Shape {
        Shape() {
            printName();
        }

        public void printName() {
            System.out.println(name());
        }

        public String name() {
            return "shape";
        }
    }

    public static class Triangle extends Shape {
        @Override
        public String name() {
            return "triangle";
        }
    }
}
0
добавлено

Вы можете использовать конечное поле и установить его в конструкторе, но IMHO предпочтительнее переопределить геттеры.

public static class Shape
{
        protected final String name;

        public Shape()
        {
                this("shape");
        }

        protected Shape(String name)
        {
                this.name = name;
        }

        public void printName()
        {
                System.out.println( name() );
        }

        public String name()
        {
                return name;
        }
}

public static class Triangle extends Shape
{
        public Triangle()
        {
               super("triangle");
        }
}
0
добавлено

Вы можете использовать конечное поле и установить его в конструкторе, но IMHO предпочтительнее переопределить геттеры.

public static class Shape
{
        protected final String name;

        public Shape()
        {
                this("shape");
        }

        protected Shape(String name)
        {
                this.name = name;
        }

        public void printName()
        {
                System.out.println( name() );
        }

        public String name()
        {
                return name;
        }
}

public static class Triangle extends Shape
{
        public Triangle()
        {
               super("triangle");
        }
}
0
добавлено
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Java & Co
Java & Co
2 370 участник(ов)

Можно обсуждать с матом и без всё, что касается жабы, вплоть до холиваров. НЕ ИМЕЕТ ОТНОШЕНИЯ К САЙТУ JAVARUSH.RU ПРАВИЛА - https://t.me/javarush/75723 Вакансии сюда - https://telegram.me/joinchat/B7IzvUCnfo6d8t3yIxKguQ По вопросам - @thedude

learn.java
learn.java
1 888 участник(ов)

Чат для начинающих и не только Статистика: https://combot.org/chat/-1001083535868 Основной чат - @jvmchat

Java Underground
Java Underground
169 участник(ов)

https://vk.com/javatutorial

Javanese Questions
Javanese Questions
109 участник(ов)

Чат предназначен для обмена знаниями строго в формате в вопрос-ответ. Тема — Java, Kotlin и Android. Вопрос должен быть предварительно прогуглен, понятно и грамотно сформулирован, помечен хэштегами. Ответ — тем более. Куски кода размером в несколько строк можно писать прямо здесь, для больших кусков кода стоит использовать http://gist.github.com/, http://pastebin.com/, https://codeshare.io/ или любой аналогичный сервис. В некоторых случаях можно прикреплять скриншоты. Стикеры и гифки запрещены. Дополнять и уточнять вопросы и ответы — редактированием исходного сообщения. Обсуждения должны приводить к редактированию вопроса/ответа и удаляться. По хештегам можно искать существующие вопросы и овтеты: #вопрос #ответ #git #generics #java #server #awt #javafx #swing #kotlin #anko #tornadofx #ktor #android #recyclerView #performance #arch #network #permissions #storage #async