【问题标题】:Behavior of strictfp keyword with implementing/extending an interface/class实现/扩展接口/类时 strictfp 关键字的行为
【发布时间】:2017-01-08 08:12:49
【问题描述】:

JLS strictfp Interfaces 指定:

strictfp 修饰符的作用是使接口声明中的所有浮点或双精度表达式都显式地为 FP-strict(第 15.4 节)。

这意味着接口中声明的所有嵌套类型都是隐式的 strictfp。

还有JLS strictfp Classes

strictfp 修饰符的作用是使接口声明中的所有浮点或双精度表达式都显式地为 FP-strict(第 15.4 节)。

这意味着接口中声明的所有方法,以及接口中声明的所有嵌套类型,都是隐式的 strictfp。

从这两段来看,没有迹象表明strictfp 在实现/扩展使用strictfp 修饰符声明的接口/类时的行为。

经过搜索,我找到了一个很好的解释strictfp关键字Use the strictfp modifier for floating-point calculation consistency across platforms的用法,它指定:

扩展 FP-strict 超类的子类不会继承严格行为。当被覆盖的方法不是 FP-strict 时,覆盖方法可以独立选择是 FP-strict,反之亦然。

它添加了:

我在扩展使用strictfp 关键字声明的类时测试了strictfp 关键字的行为,这是真的:strictfp 行为不会被扩展类的类继承,但问题是在实现使用@ 声明的接口时987654332@ 关键字不正确:strictfp 行为不被实现接口的类继承。

谁能解释strictfp 的正确行为,实现/扩展使用strictfp 修饰符声明的接口/类?

【问题讨论】:

  • “我在扩展用 strictfp 关键字声明的类时测试了 strictfp 关键字的行为,这是真的:扩展类的类不会继承 strictfp 行为,”问题是 - 你是如何测试它的?我认为这是真的,因为(来自官方文档)整个类不会是 strictfp - 只有接口中的方法。无论如何 - 你是如何进行测试的?
  • 在我看来这部分是错误的All code in any class that implements the interface。这种继承会发生在编译时间还是加载时间?在其他情况下,关键字严格应用在一个.java 源文件中,并且效果包含在一个或多个产品.class 文件中。
  • @PiotrR 我对测试的意思是我执行了多个随机示例,这些示例涵盖了strictfp 与接口、方法、构造函数和类的多种用途,并在javap -c 命令的帮助下能够调查生成代码的内容并查看strictfp 的行为是否被实现和扩展类继承。
  • @TeemuIlmonen 是的,我认为这是真的,因为在实现使用 strictfp 关键字声明的接口的类中找不到 strictfp

标签: java extends implements strictfp


【解决方案1】:

以下是我为调查您的问题所做的实验。下面的代码使用反射api来检查strictfp是否在各种场景中被声明。

结论:

  1. strictfp 接口 中声明的 Abstract 方法在实现该接口的类中不会是 strictfp
  2. strictfp 接口 中声明的默认 方法将在实现该接口的类中成为 stricfp
  3. 实现 strictfp 接口的类中的方法不会自动为 strictfp
  4. 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);
        }
    }
}

程序的输出:(在OSX上使用jdk1.8.0_91.jdk)

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

【讨论】:

  • 谢谢,您的代码可以更轻松地调查生成的代码并检查 strictfp 行为是否被继承。
【解决方案2】:

JLS §15.4 非常清楚哪些表达式是 FP 严格的,哪些不是。

如果一个类、接口或方法 X 被声明为 strictfp,那么 X 和 任何类、接口、方法、构造函数、实例初始化器, X 中的静态初始化程序或变量初始化程序被称为 FP-严格。

因此,一个表达式不是 FP-strict 当且仅当它是 不是一个常量表达式,并且它不会出现在任何中 具有 strictfp 修饰符的声明

这里的关键字是声明。如果类声明中没有strictfp修饰符,则无论该类实现什么接口,该类中的表达式都不会是FP-strict。

这与您的观察相符。从常识来看,这听起来也很合理;否则,不可能从类的任何成员(包括新引入的成员)中“重置” FP 严格性。查看javac 或HotSpot JVM 源代码,您不会发现任何strictfp 继承的迹象。

【讨论】:

  • 对我来说这个定义不是很直观。我没想到整个类都是strictfp,因为它实现了strictfp接口,但是我不知道接口中声明的抽象方法是否会在实现类中是strictfp。 JLS 15.4 中的措辞可以改进。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 1970-01-01
  • 2016-04-28
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多