Eclipse 关于 Java 中私有静态嵌套类的合成访问器的警告?

问题描述 投票:0回答:6

我的同事建议使一些 Eclipse 代码格式和警告设置更加严格。大多数这些更改都是有意义的,但我在 Java 中收到了一个奇怪的警告。这是一些重现“问题”的测试代码:

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass
    {
        public void doSomething() {}
    }

    final private InnerClass anInstance;

    {
        this.anInstance = new InnerClass();   // !!!
        this.anInstance.doSomething();
    }
}
// using "this.anInstance" instead of "anInstance" prevents another warning,
// Unqualified access to the field WeirdInnerClassJavaWarning.anInstance    

与 !使用新的警告设置在 Eclipse 中向我发出此警告:

访问封闭构造函数 WeirdInnerClassJavaWarning.InnerClass() 由合成访问器模拟 方法。提高其知名度将 提高你的表现。

这是什么意思?当我将“私有静态类”更改为“受保护静态类”时,警告消失了,这对我来说毫无意义。


编辑:我终于找到了“正确”的修复方法。这里真正的问题似乎是这个嵌套的私有静态类缺少公共构造函数。这一调整消除了警告:

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass
    {
        public void doSomething() {}
        public InnerClass() {}
    }

    final private InnerClass anInstance;

    {
        this.anInstance = new InnerClass();
        this.anInstance.doSomething();
    }
}

我希望该类是私有嵌套类(因此其他类不能访问它,包括封闭类的子类),并且我希望它是静态类。

我仍然不明白为什么使嵌套类受保护而不是私有是解决“问题”的另一种方法,但这也许是 Eclipse 的一个怪癖/错误。

(抱歉,为了更清楚,我应该将其称为 NestedClass 而不是 InnerClass。)

java eclipse nested-class java-synthetic-methods
6个回答
46
投票

您可以按如下方式消除警告:

package com.example.bugs;

public class WeirdInnerClassJavaWarning {
    private static class InnerClass {
        protected InnerClass() {}  // This constructor makes the warning go away
        public void doSomething() {}
    }

    final private InnerClass anInstance;
    {
        this.anInstance = new InnerClass(); 
        this.anInstance.doSomething();
    }
}

正如其他人所说,Eclipse 正在抱怨,因为没有显式构造函数的私有类无法从外部实例化,除非通过 Java 编译器创建的合成方法。 如果您获取代码,编译它,然后使用 jad (*) 反编译它,您将得到以下内容(重新格式化):

public class Test {
  private static class InnerClass {
    public void doSomething() {}
    // DEFAULT CONSTRUCTOR GENERATED BY COMPILER:
    private InnerClass() {}

    // SYNTHETIC METHOD GENERATED BY THE JAVA COMPILER:    
    InnerClass(InnerClass innerclass) {
      this();
    }
  }

  public Test() {
    anInstance.doSomething();
  }

  // Your instance initialization as modified by the compiler:
  private final InnerClass anInstance = new InnerClass(null);
}

如果添加受保护的构造函数,则不需要合成代码。 我认为,从理论上讲,合成代码比使用公共或受保护构造函数的非合成代码慢了一点点。

(*) 对于 jad,我链接到了一个维基百科页面...托管该程序的域已过期,但维基百科链接到了另一个我尚未亲自测试过的域。 我知道还有其他(可能是更新的)反编译器,但这是我开始使用的。 注意:在反编译最近的 Java 类文件时,它会抱怨,但它仍然做得很好。


21
投票

顺便说一句,关闭警告的设置位于“代码样式”下的 Java Errors/Warnings 页面,名为:

访问封闭类型的不可访问成员


9
投票

您无法从 WeirdInnerClassJavaWarning 实例化 InnerClass。它是私有的,JVM 不会让你这么做,但 Java 语言(出于某种原因)会。

因此,javac 会在 InnerClass 中添加一个仅返回 new InnerClass() 的方法,从而允许您从 WeirdInnerClassJavaWarning 创建 InnerClass 实例。

我认为你真的不需要摆脱它,因为性能下降会非常小。不过,如果你真的想的话,你也可以。


4
投票

我仍然不明白为什么让嵌套类受保护而不是私有是解决“问题”的另一种方法,但也许这是 Eclipse 的一个怪癖/错误

这不是 Eclipse 的怪癖/错误,只是 Java 的一个特性。 Java 语言规范,8.8.9 说:

...如果该类被声明为 protected,则默认构造函数将隐式赋予访问修饰符 protected ...


3
投票

为了帮助大家,如果您在问题中使用原始类代码和

,您会得到以下结果
javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp

原始输出,编译器添加了注释。请注意添加了合成包私有类和构造函数。

public class WeirdInnerClassJavaWarning {
    {
    }

    public WeirdInnerClassJavaWarning() {
        super();
    }
    {
    }
    private final WeirdInnerClassJavaWarning$InnerClass anInstance;
    {
        this.anInstance = new WeirdInnerClassJavaWarning$InnerClass(null);
        this.anInstance.doSomething();
    }
}

class WeirdInnerClassJavaWarning$InnerClass {

    /*synthetic*/ WeirdInnerClassJavaWarning$InnerClass(WeirdInnerClassJavaWarning$1 x0) {
        this();
    }

    private WeirdInnerClassJavaWarning$InnerClass() {
        super();
    }

    public void doSomething() {
    }
}

/*synthetic*/ class WeirdInnerClassJavaWarning$1 {
}

0
投票

您应该能够通过使用默认范围而不是私有或受保护的范围来摆脱它,即

static class InnerClass ...

还值得注意的是,我将光标放在带有警告的代码行上并按 ctrl-1,Eclipse 可能会自动为您修复此问题。

© www.soinside.com 2019 - 2024. All rights reserved.