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

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

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

22 ответов


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

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


лично я думаю, что это недостаток в дизайне 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'S получит бонус 3%.

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

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

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

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

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

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

обновление

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

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


короткий ответ: это вполне возможно, но 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())."

и последние корпус:

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

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

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

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

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

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

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

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

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

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


на самом деле мы ошибались.
Несмотря на то, что 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

;)


статические методы рассматриваются 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. Я не знаю, почему они вообще разрешили этот ярлык.


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

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

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

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

да. Практически Java позволяет переопределить статический метод, и нет теоретически, если вы переопределите статический метод в Java, то он будет компилироваться и работать плавно, но он потеряет полиморфизм, который является основным свойством Java. Вы будете везде читать, что невозможно попробовать себя в компиляции и запуске. вы получите ответ. например, если у вас есть класс Animal и статический метод eat (), и вы переопределяете этот статический метод в своем подклассе, называемом Dog. Потом когда где вы Назначьте объект Dog ссылке на животное и вызовите eat() в соответствии с Java Dog's eat() должен был быть вызван, но в статическом переопределении будет вызван Animals' 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's eat but it didn't
    }
}


Output Animal Eating

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


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

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

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

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

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

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

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

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

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


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


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

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


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


Мне нравится и двойной комментарий Джея (https://stackoverflow.com/a/2223803/1517187).
Я согласен, что это плохой дизайн Java.
Многие другие языки поддерживают переопределение статических методов, как мы видим в предыдущих комментариях. Я чувствую, что Джей тоже пришел на Яву из Дельфи, как и я.
Delphi (Object Pascal) был первым языком, реализующим ООП.
Очевидно, что многие люди имели опыт работы с этим языком, так как в прошлом это был единственный язык для напишите коммерческие продукты GUI. И-да, мы могли бы в Delphi переопределить статические методы. На самом деле, статические методы в Delphi называются "методами класса", в то время как Delphi имел другую концепцию "статических методов Delphi", которые были методами с ранней привязкой. Чтобы переопределить методы, вам пришлось использовать позднюю привязку, объявите директиву "virtual". Так что это было очень удобно и интуитивно понятно, и я ожидал бы этого на Java.


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


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


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


Что хорошего это сделать, чтобы переопределить статические методы. Нельзя вызывать статические методы через экземпляр.

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

EDIT: похоже, что из-за неудачной оплошности в языковом дизайне вы can вызов статических методов через экземпляр. Обычно никто так не делает. Моя ошибка.


простое решение: используйте экземпляр 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's singleton!";
  }

}

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

метод в Java используется для раскрытия поведения объекта / класса. Здесь, как метод static (i.e, статический метод используется только для представления поведения класса.) изменение и переопределение поведение всего класса нарушит явление одного из фундаментальных столпов объектно-ориентированного программирования i.e, высокая сплоченность. (помните, что конструктор-это особый вид метода в Java.)

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

поэтому при разработке языка программирования 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 позволяет повторно объявлять метод (статический / нестатический).

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

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

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

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


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


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

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

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

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

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


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

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

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

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

спасибо


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

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();

}   

}