【问题标题】:Why does accessing this private enum constant require a synthetic accessor?为什么访问这个私有枚举常量需要合成访问器?
【发布时间】:2016-10-02 16:20:19
【问题描述】:

我有一个类包含:

  • 一个公共的、静态的内部枚举
  • 引用 int 和枚举的私有常量
  • 私有内部类

从内部类内部引用枚举常量会生成合成访问器警告,但引用 int 常量不会。

这是为什么?如何在不使枚举常量包范围或禁用警告的情况下防止此警告? (例如,也许通过显式访问器?)

重现问题的代码:

public class Outer {
    public static enum Bar {
        A, B, C;
    }

    private static final int FOO = 0;
    private static final Outer.Bar BAR = Outer.Bar.A;

    private class Inner {
        {
            int foo = Outer.FOO;        // just fine
            Outer.Bar bar = Outer.BAR;  // synthetic accessor method warning
        }
    }
}

【问题讨论】:

  • 这只是一个猜测,但这可能是因为编译器可以优化原始整数存储并使其成为真正的编译时常量(意味着不会发生合成访问器调用),而枚举赋值,使用一个合适的对象,必须在运行时发生。
  • 我无法使用 Java 8 重现警告
  • 这个警告来自哪里?你用的是什么编译?
  • @YassinHajaj - 警告是编译器特定的,取决于您的警告选项。我相信 Eclipse 编译器是喜欢这个警告的那个。 IMO 警告比它声称要解决的问题更有害。绝大多数情况下,这些合成方法都是“有效”的有用胶水。关于每个潜在性能问题的警告都是一个滑坡,即使我想走下那个坡,我也不会从这些方法开始。

标签: java


【解决方案1】:

JLS 要求对编译时常量的访问被“内联”到消费类中,而不是在链接和运行时解析符号引用。特别是来自JLS 13.1

  1. 对作为常量变量的字段 (§4.12.4) 的引用是 在编译时解析为表示的常量值。不 对此类字段的引用应出现在二进制代码中 文件(除了在包含该字段的类或接口中,它 会有代码来初始化它)。

特别是,这意味着您的类Inner 在其编译的类文件中没有任何Outer.FOO 的痕迹。而是FOO的常量值0在编译时直接编译成Inner

添加了合成访问方法(除其他原因外)以简化 runtime 访问嵌套类之间的私有字段 - 但在 FOO 的情况下,访问已在编译时解决,因此不需要任何方法。

另一方面,Outer.BAR 不符合编译时常量处理条件 - 因为某些 String 对象以外的对象不是每个 15.28 的编译时常量:

编译时常量表达式是表示值的表达式 原始类型或不突然完成的字符串 仅使用以下内容组成...

Enum 既不是原语也不是String,因此编译时常量的特殊处理不适用,并生成合成访问器方法。

【讨论】:

  • 你有任何关于访问另一个类的static成员的合成访问方法的文档吗?
  • 关于为什么添加这些方法以及您可以对它们做些什么的信息有很多。就我个人而言,我认为它们是无害的——编译器添加了胶水,这样事情就可以工作了。性能警告有点像 IMO 的红鲱鱼 - 在 99% 的情况下,内联将消除运行时的实际调用。请参阅here 进行讨论。
  • ... 和here,如果您想了解添加这些内容的原因。全部通过 Google 找到。
猜你喜欢
  • 2014-03-13
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 2022-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多