Поведение ключевого слова strictfp с внедрением/расширением интерфейса/класса

JLS strictfp Интерфейсы определяет, что:

Эффект модификатора strictfp состоит в том, чтобы сделать все float или double выражения в объявлении интерфейса явно FP-строгими (§15.4).

Это означает, что все вложенные типы, объявленные в интерфейсе, неявно строго определены.

И JLS strictfp Классы:

Эффект модификатора strictfp состоит в том, чтобы сделать все float или double выражения в объявлении интерфейса явно FP-строгими (§15.4).

Это означает, что все методы, объявленные в интерфейсе, и все вложенные типы, объявленные в интерфейсе, неявно строго определены.

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

После поиска я нашел хорошее объяснение использования ключевого слова strictfp Использовать модификатор strictfp для согласования вычислений с плавающей запятой между платформами, и он указывает, что:

Строгое поведение не наследуется подклассом, который расширяет FP-строгий суперкласс. Метод переопределения может независимо выбирать FP-строгий, если переопределенный метод не является, или наоборот.

И добавляет: введите описание изображения здесь

Я тестировал поведение ключевого слова strictfp при расширении класса, объявленного с ключевым словом strictfp, и это правда: поведение strictfp не наследуется классами, расширяющими класс, но проблема заключается в реализации интерфейса, объявленного с помощью strictfp Неверное ключевое слово: поведение strictfp не наследуется классами, реализующими интерфейс.

Может ли кто-нибудь объяснить мне правильное поведение strictfp с реализацией/расширением интерфейса/класса, объявленного с помощью модификатора strictfp?

Ответы

Ответ 1

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

Выводы:

  • Абстрактные методы, объявленные в формате strictfp, не будут strictfp в классе, реализующем интерфейс
  • Стандартные методы, объявленные в строчном интерфейсе, будут stricfp в классе, реализующем интерфейс
  • Методы в классах, реализующих строковый интерфейс, не будут автоматически strictfp
  • Все методы, объявленные в внутренних классах интерфейса strictfp, будут иметь модификатор stricfp

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

Обратите внимание, что модификатор strictfp не применяется к абстрактным методам.

import java.lang.reflect.Modifier;

strictfp interface StrictInterface {

    void someInterfaceMethod();

    default void someInterfaceDefaultMethod() {}

    class InnerTest {
        public static void innerMethod() {}
    }
}

class Impl implements StrictInterface {
    @Override
    public void someInterfaceMethod() {}

    public strictfp void someClassMethod() {}

    public void someClassMethod2() {}
}

public class Test {
    public static void main(String argv[]) {

        checkModifiers(Impl.class, "someInterfaceMethod");
        checkModifiers(Impl.class, "someClassMethod");
        checkModifiers(Impl.class, "someClassMethod2");

        checkModifiers(Impl.class.getInterfaces()[0], "someInterfaceDefaultMethod");
        checkModifiers(StrictInterface.InnerTest.class, "innerMethod");
    }
    public static void checkModifiers(Class clazz, String m) {
        try {
            int mod = clazz.getDeclaredMethod(m, new Class[0]).getModifiers();
            String res = m + " modifiers: " + Modifier.toString(mod);
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
    }
}

Вывод программы: (используя jdk1.8.0_91.jdk на OSX)

someInterfaceMethod modifiers: public
someClassMethod modifiers: public strictfp
someClassMethod2 modifiers: public
someInterfaceDefaultMethod modifiers: public strictfp
innerMethod modifiers: public static strictfp

Ответ 2

JLS §15.4 довольно ясно, какие выражения FP-строгие, а какие нет.

Если класс, интерфейс или метод X объявлен strictfp, то X и любой класс, интерфейс, метод, конструктор, инициализатор экземпляра, статический инициализатор или инициализатор переменной в X называется FP-строгое.

Отсюда следует, что выражение не является FP-строгим тогда и только тогда, когда оно не постоянное выражение, и оно не отображается в пределах любого Объявление, имеющее модификатор strictfp.

Ключевое слово здесь Объявление. Если в объявлении класса нет модификатора strictfp, выражения внутри этого класса не будут FP-строгими, независимо от того, что он реализует в этом классе.

Это соответствует вашим наблюдениям. Это также звучит разумно из общего положения; иначе было бы невозможно "reset" FP-строгость от любого члена класса, включая вновь введенных членов. Рассматривая исходный код javac или HotSpot JVM, вы не найдете признаков наследования strictfp.