关于 Java 中私有静态嵌套类的合成访问器的 Eclipse 警告?
Posted
技术标签:
【中文标题】关于 Java 中私有静态嵌套类的合成访问器的 Eclipse 警告?【英文标题】:Eclipse warning about synthetic accessor for private static nested classes in Java? 【发布时间】:2010-10-29 14:13:55 【问题描述】:我的同事建议让一些 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。)
【问题讨论】:
我不明白一点:拥有一个不能被其他人使用的内部类有什么用处?我想我会把这个类放在一个单独的类文件中,让其他程序员选择它是否对其他作用域有用。 【参考方案1】:您不能从 WeirdInnerClassJavaWarning 实例化 InnerClass。它是私有的,JVM 不会让你这样做,但 Java 语言(出于某种原因)会。
因此,javac 会在 InnerClass 中创建一个额外的方法,该方法只会返回 new InnerClass(),因此允许您从 WeirdInnerClassJavaWarning 创建 InnerClass 实例。
我不认为你真的需要摆脱它,因为性能下降会非常小。不过,如果你真的想,你可以。
【讨论】:
+1 性能提升在现代 JVM 上应该是完全无关紧要的。 Eclipse 只是在这里过于热情,我会完全关闭该警告。 “您不能从 WeirdInnerClassJavaWarning 实例化 InnerClass。它是私有的,JVM 不允许您这样做,但 Java 语言(出于某种原因)可以。”没有构造函数存在,Java 语言将自动创建一个无参数的公共构造函数,不存在。 Eclipse 警告说,这种魔力正在发生。 我猜这个构造函数在私有内部类的情况下是私有的。否则这个警告没有任何意义。【参考方案2】:您应该能够通过使用默认范围而不是私有或受保护范围来摆脱它,即
static class InnerClass ...
还值得注意的是,我将光标放在带有警告的代码行上并按 ctrl-1,Eclipse 可能会自动为您修复此问题。
【讨论】:
谢谢,但我不希望这样,它应该对封闭类以外的类不可见。 在这种情况下,您可能想要取消警告,因为 Eclipse 的性能导向警告与您的需求无关。 相关配置为“访问封闭类型的不可访问成员”【参考方案3】:您可以按如下方式摆脱警告:
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,我链接到了一个 Wikipedia 页面……托管此程序的域已过期,但 Wikipedia 链接到另一个我自己没有测试过的域。我知道还有其他(可能是更新的)反编译器,但这是我开始使用的。注意:在反编译最近的 Java 类文件时它抱怨,但它仍然做得很好。
【讨论】:
我假设您在我进行编辑之前正在发帖。无论如何,这似乎是正确的答案。 是的,你和我同时打字。我已经扩展了我的答案,还解释了为什么你会收到 Eclipse 警告。 +1 关于反编译器,我从来不知道有这样的事情。听起来我应该为 Eclipse 提交一个错误,他们应该更改此警告的文本,以便更清楚这意味着什么以及应该修复什么。 除非这是一个 J2ME 项目,否则最好的解决方案是禁用 Eclipse 中的警告并编写代码以符合您的意图。在 JIT 之后,性能影响将可以忽略不计或为零。 @Darron & Co. 我看不出表演应该从何而来。编译器生成合成方法,因此在运行时它应该看起来就像您自己放置它时一样。还是我错过了什么?【参考方案4】:我仍然不明白为什么让嵌套类受保护而不是私有是解决“问题”的另一种方法,但这可能是 Eclipse 的一个怪癖/错误
这不是 Eclipse 的怪癖/错误,只是 Java 的一个特性。 Java Language Specification, 8.8.9 说:
...如果类被声明为protected,则默认构造函数被隐式赋予访问修饰符protected ...
【讨论】:
...和protected 和private 对封闭类有不同的影响?我认为唯一的区别是如何授予子类的访问权限。 它在源代码级别(编译器)没有影响,但在字节代码级别(虚拟机)。据我所知,JVM 不知道嵌套类,这就是为什么你会为它们获得一个额外的 .class 文件。编译器必须创建合成方法,以便“外部”类可以访问嵌套类的私有成员(在运行时)。 (顺便说一句:受保护的还包括包访问,这足以避免警告)(顺便说一句:按照 JLS 的定义,静态嵌套类不是内部类...)【参考方案5】:顺便说一句,关闭警告的设置在“代码样式”下的Java错误/警告页面中,被称为:
访问封闭类型的不可访问成员
【讨论】:
对我来说已经设置为忽略,但我仍然看到警告。也许朱诺号发生了一些变化。 是否有可能在项目特定设置中设置为警告? 我知道这看起来多么可悲,但是 - 如果警告仍然存在,请在某处添加一些字符并保存文件。警告将在之后消失。 在 Kepler 中我可以忽略此警告【参考方案6】:为了帮助大家,如果您在问题中使用原始类代码,您会得到以下结果:
javac -XD-printflat WeirdInnerClassJavaWarning.java -d tmp
原始输出,编译器添加了 cmets。注意添加了合成包私有类和构造函数。
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
【讨论】:
以上是关于关于 Java 中私有静态嵌套类的合成访问器的 Eclipse 警告?的主要内容,如果未能解决你的问题,请参考以下文章
私有的嵌套类(内部或静态)是不是可能具有具有公共访问权限的方法?