Подтвердить что ты не робот

Почему Java не позволяет переопределять статические методы?

Почему невозможно переопределить статические методы?

Если возможно, используйте пример.

4b9b3361

Ответ 1

Переопределение зависит от наличия экземпляра класса. Точка полиморфизма заключается в том, что вы можете подклассифицировать класс, а объекты, реализующие эти подклассы, будут иметь разные типы поведения для тех же методов, которые определены в суперклассе (и переопределены в подклассах). Статический метод не связан ни с одним экземпляром класса, поэтому концепция не применима.

Существовали два соображения, вовлекающие Java-дизайн, который повлиял на это. Одной из них было беспокойство по поводу производительности: было много критики Smalltalk о том, что она слишком медленная (сбор мусора и полиморфные вызовы являются частью этого), и разработчики Java были настроены избегать этого. Другим было решение о том, что целевой аудиторией Java являются разработчики на С++. Создание статических методов работает так, как они это делают, с пользой для программистов на C++, а также очень быстро, потому что нет необходимости ждать, пока время выполнения не выяснит, какой метод вызывать.

Ответ 2

Лично я считаю, что это недостаток в дизайне Java. Да, да, я понимаю, что нестатические методы привязаны к экземпляру, а статические методы привязаны к классу и т.д. И т.д. Однако рассмотрим следующий код:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

Этот код не будет работать так, как вы могли бы ожидать. А именно, SpecialEmployee получает 2% бонус, как обычные сотрудники. Но если вы удалите "статические", то SpecialEmployee получит 3% бонус.

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

Мне кажется весьма правдоподобным, что вы можете сделать статичным getBonusMultiplier статическим. Возможно, вы хотите показать мультипликатор бонуса для всех категорий сотрудников без необходимости иметь экземпляр сотрудника в каждой категории. Какой смысл искать такие примеры? Что делать, если мы создаем новую категорию сотрудников и пока не имеем каких-либо сотрудников, назначенных ей? Это довольно логически статическая функция.

Но это не сработает.

И да, да, я могу думать о любом количестве способов переписать вышеприведенный код, чтобы он работал. Я не говорю о том, что он создает неразрешимую проблему, но что он создает ловушку для неосторожного программиста, потому что язык не ведет себя так, как я думаю, разумный человек будет ожидать.

Возможно, если бы я попытался написать компилятор для языка ООП, я бы быстро понял, почему его реализовать, чтобы статические функции могли быть переопределены, было бы трудно или невозможно.

Или, возможно, есть веская причина, почему Java ведет себя таким образом. Может ли кто-нибудь указать на преимущество этого поведения, какую-то категорию проблемы, которая облегчается этим? Я имею в виду, не просто указывайте мне на спецификацию языка Java и скажите "см., Это документировано, как оно себя ведет". Я знаю это. Но есть ли веская причина, почему ему так надо? (Кроме того, очевидно, что "заставить работать правильно было слишком сложно"...)

Обновление

@VicKirk: Если вы имеете в виду, что это "плохой дизайн", потому что он не подходит, как Java обрабатывает статику, мой ответ: "Ну, конечно,". Как я сказал в своем оригинальном посте, это не сработает. Но если вы имеете в виду, что это плохой дизайн в том смысле, что в нем будет что-то принципиально неправильное с языком, где это сработало, то есть, где статика может быть переопределена, как и виртуальные функции, что это каким-то образом приведет к двусмысленности, или было бы невозможно эффективно или что-то подобное, я отвечаю: "Почему? Что не так с концепцией?"

Я думаю, что пример, который я даю, - очень естественная вещь, которую хочется сделать. У меня есть класс, который имеет функцию, которая не зависит от каких-либо данных экземпляра и которую я могу очень разумно вызывать независимо от экземпляра, а также желать вызвать из метода экземпляра. Почему это не работает? На протяжении многих лет я сталкивался с этой ситуацией довольно много. На практике я обхожу его, создавая функцию virtual, а затем создаю статический метод, единственной целью которого является статический метод, который передает вызов виртуальному методу с фиктивным экземпляром. Это похоже на очень крутой способ добраться туда.

Ответ 3

Короткий ответ: это вполне возможно, но Java этого не делает.

Вот какой код, который иллюстрирует текущее состояние дел в Java:

Файл Base.java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

Файл Child.java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

Если вы запустите это (я сделал это на Mac, с Eclipse, используя Java 1.6), вы получаете:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

Здесь единственными случаями, которые могут быть сюрпризом (и о чем идет речь), являются первый случай:

"Тип времени выполнения не используется для определения того, какие статические методы вызывают, даже если вызывается с экземпляром объекта (obj.staticMethod())."

и последний случай:

"При вызове статического метода из объектного метода класса выбранный статический метод является единственным, доступным из самого класса, а не из класса, определяющего тип времени выполнения объекта.

Вызов с экземпляром объекта

Статический вызов разрешается во время компиляции, тогда как вызов нестатического метода разрешается во время выполнения. Обратите внимание, что хотя статические методы наследуются (от родителя), они не переопределяются (дочерним). Это может быть неожиданностью, если вы ожидали иначе.

Вызов из метода объекта

Вызов метода объекта разрешается с использованием типа времени выполнения, но вызовы метода static (class) разрешаются с использованием типа времени компиляции (объявленного).

Изменение правил

Чтобы изменить эти правила, чтобы последний вызов в примере с именем Child.printValue(), статические вызовы должны были быть снабжены типом во время выполнения, а не компилятором, разрешающим вызов во время компиляции с объявленным класс объекта (или контекста). Статические вызовы затем могут использовать иерархию (динамического) типа для разрешения вызова, так же, как и вызовы метода объекта.

Это легко выполнимо (если мы изменили Java: -O) и не совсем необоснованно, однако у него есть интересные соображения.

Основное соображение состоит в том, что нам нужно решить, какие вызовы статических методов должны делать это.

В настоящий момент Java имеет этот "quirk" на языке, на котором obj.staticMethod() вызовы заменяются на вызовы ObjectClass.staticMethod() (обычно с предупреждением). [Примечание: ObjectClass - это тип времени компиляции obj.] Это были бы хорошие кандидаты для переопределения таким образом, взяв тип времени выполнения obj.

Если бы мы это сделали, это затрудняло бы считывание методов: статические вызовы в родительском классе потенциально могли бы динамически "перенаправляться". Чтобы этого избежать, нам пришлось бы вызвать статический метод с именем класса - и это делает вызовы более понятными с иерархией типов времени компиляции (как сейчас).

Другие способы вызова статического метода более сложны: this.staticMethod() должен означать то же самое, что и obj.staticMethod(), принимая тип времени выполнения this. Однако это может вызвать некоторые головные боли с существующими программами, которые называют (по-видимому, локальные) статические методы без декорации (что, возможно, эквивалентно this.method()).

А как насчет неприкрашенных звонков staticMethod()? Я предлагаю им сделать то же самое, что и сегодня, и использовать контекст локального класса, чтобы решить, что делать. В противном случае возникла бы большая путаница. Конечно, это означает, что method() будет означать this.method(), если method был нестационарным методом, а ThisClass.method(), если method был статическим методом. Это еще один источник путаницы.

Другие соображения

Если мы изменили это поведение (и сделало статические вызовы потенциально динамически нелокальными), мы, вероятно, хотели бы пересмотреть значение final, private и protected в качестве квалификаторов в методах static класса, Мы все должны были бы привыкнуть к тому, что методы private static и public final не переопределены и поэтому могут быть безопасно разрешены во время компиляции и "безопасны" для чтения в качестве локальных ссылок.

Ответ 4

На самом деле мы ошибались.
Несмотря на то, что Java не позволяет вам переопределять статические методы по умолчанию, если вы тщательно изучаете документацию классов класса и метода в Java, вы все равно можете найти способ эмуляции статических методов, переопределяющих следующие методы:

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

Результат:

0.02
0.02
0.02
0.03

что мы пытались достичь:)

Даже если мы объявим третью переменную Carl как RegularEmployee и присвоим ей экземпляр SpecialEmployee, в первом случае мы по-прежнему будем иметь вызов метода RegularEmployee и вызов метода SpecialEmployee во втором случае

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

просто посмотрите на консоль вывода:

0.02
0.03

;)

Ответ 5

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

Это может быть концептуально возможно, если вы можете вызвать статические методы из объектов класса (например, в таких языках, как Smalltalk), но это не так в Java.

ИЗМЕНИТЬ

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

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

Вы можете размышлять над классами, но он останавливается там. Вы не вызываете статический метод, используя clazz1.staticMethod(), но используя MyClass.staticMethod(). Статический метод не привязан к объекту и, следовательно, не существует понятия this и super в статическом методе. Статический метод - глобальная функция; как следствие, также нет понятия полиморфизма, и поэтому переопределение метода не имеет смысла.

Но это возможно, если MyClass был объектом во время выполнения, на котором вы вызываете метод, как в Smalltalk (или, может быть, JRuby, как один комментарий, но я ничего не знаю о JRuby).

О да... еще одна вещь. Вы можете вызвать статический метод через объект obj1.staticMethod(), но это действительно синтаксический сахар для MyClass.staticMethod(), и его следует избегать. Обычно это вызывает предупреждение в современной среде IDE. Я не знаю, почему они когда-либо допускали этот ярлык.

Ответ 6

Переопределение метода становится возможным благодаря динамической диспетчеризации что означает, что объявленный тип объекта не определяет его поведение, а скорее его время выполнения Тип:

Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"

Даже если оба lassie и kermit объявлены как объекты типа Animal, их поведение (метод .speak()) изменяется, потому что динамическая диспетчеризация будет bind вызов метода .speak() к реализации во время выполнения - не во время компиляции.

Теперь, где ключевое слово static начинает иметь смысл: слово "статический" является антонимом для "динамического".. Поэтому причина, по которой вы не можете переопределить статические методы, заключается в том, что динамическая диспетчеризация на статических членах - , потому что статическое буквально означает "не динамический". Если они отправляются динамически (и, следовательно, могут быть переопределены), ключевое слово static просто не имеет смысла.

Ответ 7

Да. Практически Java позволяет переопределить статический метод, и нет теоретически, если вы переопределите статический метод в Java, тогда он будет компилироваться и работать плавно, но он потеряет Полиморфизм, который является основным свойством Java. Вы будете читать повсюду, что невозможно попробовать себя в компиляции и запуске. вы получите ответ. например, если у вас есть класс Animal и статический метод eat(), и вы переопределяете этот статический метод в своем подклассе, вызывается его Dog. Затем, когда вы назначаете объект "Собака" в "Справочник животных" и вызывается "eat"() в соответствии с Java Dog eat(), нужно было вызвать, но в статическом режиме "Переезды животных" ("Будет").

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog eat but it didn't
    }
}


Output Animal Eating

Согласно Принципу Полиморфизма Явы, Выход должен быть Dog Eating.
Но результат был другим, потому что для поддержки Polymorphism Java использует Late Binding, что означает, что методы вызываются только во время выполнения, но не в случае статических методов. В статических методах компилятор вызывает методы во время компиляции, а не во время выполнения, поэтому мы получаем методы в соответствии с ссылкой, а не по объекту, ссылку a, содержащую то, что вы можете сказать. Практически он поддерживает статическое переполнение, но теоретически это не делает "т.

Ответ 8

В Java (и многих языках ООП, но я не могу говорить за всех, а некоторые вообще не имеют статичности), все методы имеют фиксированную подпись - параметры и типы. В виртуальном методе подразумевается первый параметр: ссылка на сам объект и при вызове внутри объекта компилятор автоматически добавляет this.

Нет никакой разницы для статических методов - они все еще имеют фиксированную подпись. Однако, объявив метод static, вы прямо заявили, что компилятор не должен включать параметр подразумеваемого объекта в начале этой подписи. Поэтому любой другой код, который вызывает это, не должен пытаться помещать ссылку на объект в стеке. Если это так, то выполнение метода не будет работать, так как параметры будут не в том месте - сдвинуты на один - в стеке.

Из-за этой разницы между ними; виртуальные методы всегда имеют ссылку на объект контекста (т.е. this), поэтому можно ссылаться на что-либо внутри кучи, принадлежащей этому экземпляру объекта. Но со статическими методами, поскольку эта ссылка не передана, этот метод не может получить доступ к каким-либо объектным переменным и методам, поскольку контекст неизвестен.

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

Как кто-то спросил в комментарии к op - какова ваша причина и цель для этой функции?

Я не очень хорошо знаю Ruby, так как это упоминалось OP, я провел некоторое исследование. Я вижу, что в классах Ruby действительно особый вид объекта, и можно создавать (даже динамически) новые методы. Классы - это объекты полного класса в Ruby, они не находятся на Java. Это то, что вам нужно будет принять при работе с Java (или С#). Это не динамические языки, хотя С# добавляет некоторые формы динамических. На самом деле Ruby не имеет "статических" методов, насколько я мог найти - в этом случае это методы для объекта singleton class. Затем вы можете переопределить этот синглтон с новым классом, а методы в предыдущем объекте класса вызовут те, которые определены в новом классе (правильно?). Поэтому, если вы вызвали метод в контексте исходного класса, он все равно выполнил бы только исходную статику, но вызов метода в производном классе вызовет методы либо из родительского, либо подкласса. Интересно, и я вижу в этом какую-то ценность. Требуется другой шаблон мысли.

Поскольку вы работаете на Java, вам нужно будет приспособиться к этому. Почему они это сделали? Ну, возможно, чтобы улучшить производительность в то время на основе технологии и понимания, которые были доступны. Компьютерные языки постоянно развиваются. Вернитесь достаточно далеко, и нет такой вещи, как ООП. В будущем появятся и другие новые идеи.

EDIT. Еще один комментарий. Теперь, когда я вижу различия и как сам разработчик Java/С#, я могу понять, почему ответы, которые вы получаете от разработчиков Java, могут сбивать с толку, если вы исходите с такого языка, как Ruby. Методы Java static не совпадают с методами Ruby class. Разработчикам Java будет трудно понять это, так же как и те, кто работает в основном с языком Ruby/Smalltalk. Я вижу, как это также будет очень смущать тем фактом, что Java также использует метод класса, как другой способ говорить о статических методах, но этот же термин используется по-разному Ruby. Java не имеет методов класса стиля Ruby (извините); Ruby не имеет статических методов стиля Java, которые на самом деле являются просто старыми процедурными функциями стиля, как показано на C.

Кстати, спасибо за вопрос! Я узнал что-то новое для меня сегодня о методах класса (стиль Ruby).

Ответ 9

Ну... ответ НЕТ, если вы думаете с точки зрения того, как метод override должен вести себя на Java. Но вы не получаете никакой ошибки компилятора, если пытаетесь переопределить статический метод. Это означает, что если вы попытаетесь переопределить, Java не остановит вас; но вы, конечно, не получаете того же эффекта, что и для нестатических методов. Переопределение на Java просто означает, что конкретный метод будет вызываться в зависимости от типа времени выполнения объекта, а не от его типа времени компиляции (что имеет место при переопределении статических методов). Хорошо... любые догадки по причине, почему они ведут себя странно? Поскольку они являются методами класса и, следовательно, доступ к ним всегда разрешается во время компиляции только с использованием информации типа времени компиляции. Доступ к ним с использованием ссылок на объекты - это дополнительная свобода, предоставляемая разработчиками Java, и мы не должны думать об остановке этой практики только тогда, когда они ее ограничивают: -)

Пример: попробуйте выяснить, что произойдет, если мы попробуем переопределить статический метод: -

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

Выход: -
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod

Обратите внимание на вторую строку вывода. Если бы staticMethod был переопределен, эта строка должна была быть идентичной третьей строке, поскольку мы вызываем "staticMethod()" на объект Runtime Type как "SubClass", а не как "SuperClass". Это подтверждает, что статические методы всегда разрешаются с использованием только информации типа времени компиляции.

Ответ 10

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

Ответ 11

В общем, не имеет смысла позволять "переопределять" статические методы, поскольку не было бы хорошего способа определить, какой вызов вызывать во время выполнения. Взяв пример Employee, если мы вызываем RegularEmployee.getBonusMultiplier() - какой метод предполагается выполнить?

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

Ответ 12

Мне нравится и двойной комментарий Jay (fooobar.com/questions/1927/...).
Я согласен, что это плохой дизайн Java.
Многие другие языки поддерживают переопределение статических методов, как мы видим в предыдущих комментариях. Я чувствую, что Джей тоже пришел на Яву из Delphi, как я.
Delphi (Object Pascal) был первым языком, реализующим ООП.
Очевидно, что многие люди имеют опыт работы на этом языке, поскольку в прошлом он был единственным языком для написания коммерческих графических продуктов. И - да, мы могли бы в Delphi переопределить статические методы. Фактически, статические методы в Delphi называются "методами класса", в то время как у Delphi была другая концепция "статических методов Delphi", которые были методами с ранним связыванием. Чтобы переопределить методы, которым вы должны были использовать позднюю привязку, объявите "виртуальную" директиву. Это было очень удобно и интуитивно, и я ожидал бы этого на Java.

Ответ 13

С помощью переопределения мы можем создать полиморфную природу в зависимости от типа объекта. Статический метод не имеет отношения к объекту. Поэтому java не может поддерживать переопределение статического метода.

Ответ 14

Переопределение на Java просто означает, что конкретный метод будет вызываться на основе типа времени выполнения объекта, а не его типа времени компиляции (что имеет место с переопределенными статическими методами). Поскольку статические методы являются методами класса, они не являются методами экземпляра, поэтому они не имеют никакого отношения к тому, какая ссылка указывает на какой объект или экземпляр, потому что из-за характера статического метода он относится к определенному классу. Вы можете обновить его в подклассе, но этот подкласс ничего не знает о статических методах родительского класса, поскольку, как я уже сказал, он специфичен только для того класса, в котором он был объявлен. Доступ к ним с использованием ссылок на объекты - это дополнительная свобода, предоставляемая разработчиками Java, и мы, разумеется, не должны думать о том, чтобы остановить эту практику только тогда, когда они ограничивают ее более подробными сведениями и примером http://faisalbhagat.blogspot.com/2014/09/method -overriding-и-метод-hiding.html

Ответ 15

Ответ на этот вопрос прост, метод или переменная, помеченные как static, принадлежат только классу. Поэтому статический метод не может быть унаследован в подклассе, потому что они принадлежат только суперклассу.

Ответ 16

Какая польза от переопределения статических методов. Вы не можете вызвать статические методы через экземпляр.

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

EDIT: Похоже, что через неудачный надзор в дизайне языка вы можете вызвать статические методы через экземпляр. Как правило, никто этого не делает. Мой плохой.

Ответ 17

Посредством переопределения вы достигаете динамического полиморфизма. Когда вы говорите о переопределении статических методов, слова, которые вы пытаетесь использовать, противоречивы.

Static говорит - время компиляции, переопределение используется для динамического полиморфизма. Оба они противоположны по своей природе и поэтому не могут использоваться вместе.

Динамическое полиморфное поведение возникает, когда программист использует объект и получает доступ к методу экземпляра. JRE отобразит различные методы экземпляра разных классов на основе того, какой тип объекта вы используете.

Когда вы говорите, переопределяя статические методы, статические методы, к которым мы будем обращаться, используя имя класса, которое будет связано во время компиляции, так что во время выполнения со статическими методами нет концепции связывания методов. Таким образом, термин "переопределяющие" статические методы не имеет никакого значения.

Примечание. Даже если вы обращаетесь к методу класса с объектом, все еще java-компилятор достаточно интеллектуальный, чтобы его найти, и будет выполнять статические ссылки.

Ответ 18

Простое решение: используйте экземпляр singleton. Это позволит переопределить и наследовать.

В моей системе у меня есть класс SingletonsRegistry, который возвращает экземпляр для переданного класса. Если экземпляр не найден, он создается.

Класс языка Haxe:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it singleton!";
  }

}

Ответ 19

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

Ответ 20

Статический метод, переменный, блок или вложенный класс относится ко всему классу, а не к объекту.

Метод в Java используется для выявления поведения объекта/класса. Здесь, поскольку метод статический (т.е. Статический метод используется для представления поведения только класса). изменение/переопределение поведение всего класса нарушит явление одного из основополагающих принципов объектно-ориентированного программирования, т.е. высокой степени сцепления. (помните, что конструктор - это особый вид метода в Java.)

Высокая сплоченность. Один класс должен иметь только одну роль. Например: класс автомобиля должен производить только автомобильные объекты, а не велосипеды, грузовики, самолеты и т.д. Но класс Car может иметь некоторые функции (поведение), которые принадлежат только ему.

Поэтому при разработке Java-языка программирования. Разработчики языка думали, что позволить разработчикам придерживаться какого-либо поведения класса для себя только путем создания статического метода.


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

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

Это потому, что здесь мы не переопределяем метод, но мы просто повторно объявляем его. Java позволяет повторно объявить метод (статический/нестатический).

Удаление статического ключевого слова из метода getVehileNumber() класса Car приведет к ошибке компиляции. Поскольку мы пытаемся изменить функциональность статического метода, которая принадлежит только классу Vehicle.

Кроме того, если getVehileNumber() объявлен как final, тогда код не будет компилироваться, так как последнее ключевое слово ограничивает программиста повторным объявлением метода.

public static final int getVehileNumber() {
return VIN;     }

В целом, это разработчики программного обеспечения для использования статических методов. Я лично предпочитаю использовать статические методы для выполнения некоторых действий без создания какого-либо экземпляра класса. Во-вторых, чтобы скрыть поведение класса из внешнего мира.

Ответ 21

Теперь, видя ответы выше, все знают, что мы не можем переопределять статические методы, но не следует неправильно понимать концепцию доступа к статическим методам из подкласса.

Мы можем получить доступ к статическим методам суперкласса с подклассом, если этот статический метод не был скрыт новым статическим методом, определенным в подклассе.

Пример, см. ниже код: -

public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}

Вывод: -

SuperClass saying Hello

Смотрите Java oracle docs и найдите Что вы можете сделать в подклассе для получения дополнительной информации о скрытии статического методы в подклассе.

Спасибо

Ответ 22

Следующий код показывает, что это возможно:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

}