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

Вот краткий пример из раздела JLS 8.4.8.2.

class Super {
    static String greeting() { return "Goodnight"; }
    String name() { return "Richard"; }
}
class Sub extends Super {
    static String greeting() { return "Hello"; }
    String name() { return "Dick"; }
}
class Test {
    public static void main(String[] args) {
        Super s = new Sub();
        System.out.println(s.greeting() + ", " + s.name());
    }
}

Согласно обсуждению примера, выход работает main() будет "Спокойной ночи, Дик". Это потому, что статические методы вызываются на основе статического типа переменной / выражения, к которому они вызваны.

Вот мой вопрос: любой даже умеренно чувствительный к потоку компилятор может выяснить, что тип любого объекта хранится в s на момент звонка всегда должно быть SubТаким образом, если бы компилятору было разрешено использовать эту информацию, даже при вызове статических методов можно было бы почувствовать динамическое связывание. Почему это не разрешено? Есть ли у Java явная цель, чтобы каждый компилятор создавал байт-код, который ведет себя точно так же, или есть какая-то другая причина?

2 ответа

Решение

На самом деле здесь s.greeting()эквивалентно Super.greeting() так как s определяется как Super и статические методы не заботятся об экземплярах классов. Они общеклассные, как вы наверняка знаете. Так что нет никакого смысла вызывать статический метод из экземпляра класса. И конечно же экземпляр s это Sub() как вы указали, поэтому нестатический метод Sub.name() называется.

Из официальных руководств Java:

Вы также можете ссылаться на статические поля с помощью ссылки на объект, такой как

myBike.numberOfBicycles

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

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

Это не слишком специфично для Java. Вообразите свою "интеллектуальную" компиляцию с s.getClass().greeting() в:

class A extends Sub {
    static String greeting() { return "Allo"; }
}
class B extends Sub {
    static String greeting() { return "Brrr"; }
}
Super s = condition? new A() : new B();
assert s.greeting.equals(Sub.greeting()); // If compiler cannot infer condition.

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

Я скорее думаю, что ошибка в Java заключается в том, что s.greeting() позволено.

Поскольку для статического наследования нет смысла, лучше не изобретать такую ​​функцию.

Другие вопросы по тегам