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

Цитирование HTML 4 spec : «Начальный тег TBODY всегда требуется, за исключением случаев, когда таблица содержит только одно тело таблицы, а также не имеет разделов таблицы или ног. Терминальный тег TBODY может всегда быть безопасно опущен .

Итак, у вас должен быть тэг , если у вас есть или

См. также: MDN

499
задан Michael Myers 8 February 2010 в 17:14
поделиться

7 ответов

Для gcc/g + +

gcc -save-temps -fverbose-asm prog.c

Это приведет к созданию prog.s с некоторыми комментариями к переменным, используемым в каждой asm строке:

    movl    $42, -24(%ebp)  #, readme
    movl    -16(%ebp), %eax # pid, pid
    movl    %eax, 4(%esp)   # pid,
    movl    $.LC0, (%esp)   #,
    call    printf  #
-121--2029766-

Чтобы объявить его глобальной функцией, просто удалите все специфичные для jQuery биты. Что-то вроде этого:

function getList(url, gkey) {
    var returned = null;
    if (url.indexOf("?") != -1){
    var list = url.split("?")[1].split("&"), gets = [];
    for (var ind in list){
        var kv = list[ind].split("=");
        if (kv.length>0) {
            gets[kv[0]] = kv[1];
        }
    }

    returned = gets;

    if (typeof gkey != "undefined") {
        if (typeof gets[gkey] != "undefined") {
            returned = gets[gkey];
        }
    }

    return returned;
}

И тогда вы должны иметь возможность называть это откуда угодно.

-121--912â-

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

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

479
ответ дан 22 November 2019 в 22:31
поделиться

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

18
ответ дан 22 November 2019 в 22:31
поделиться

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

5
ответ дан 22 November 2019 в 22:31
поделиться

Лично я считаю, что это недостаток в конструкции 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 обрабатывает статику, мой ответ это: «Ну да, конечно». Как я уже сказал в своем исходном посте, это не работает. Но если вы имеете в виду, что это плохой дизайн в том смысле, что было бы что-то в корне неправильное с языком, на котором это работало, т.е.где статика может быть переопределена так же, как виртуальные функции, что это каким-то образом внесет двусмысленность или будет невозможно реализовать эффективно или что-то подобное, я отвечаю: «Почему? Что не так с концепцией?»

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

180
ответ дан 22 November 2019 в 22:31
поделиться

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

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

РЕДАКТИРОВАТЬ: Похоже, что из-за досадной оплошности в дизайне языка вы можете вызывать статические методы через экземпляр. Обычно этого никто не делает. Виноват.

2
ответ дан 22 November 2019 в 22:31
поделиться

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

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

4
ответ дан 22 November 2019 в 22:31
поделиться

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ : еще один комментарий.Теперь, когда я вижу различия и как разработчик Java / C #, я могу понять, почему ответы, которые вы получаете от разработчиков Java, могут сбивать с толку, если вы пришли с такого языка, как Ruby. Статические методы Java не то же самое, что методы класса Ruby . Разработчикам Java будет трудно понять это, как и тем, кто работает в основном с таким языком, как Ruby / Smalltalk. Я понимаю, что это также сильно сбивает с толку тот факт, что Java также использует «метод класса» как еще один способ говорить о статических методах, но этот же термин по-другому используется в Ruby. В Java нет методов класса в стиле Ruby (извините); В Ruby нет статических методов в стиле Java, которые на самом деле представляют собой просто старые функции процедурного стиля, как в C.

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

5
ответ дан 22 November 2019 в 22:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: