我的同事建议将几个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来更清楚。)
答案 0 :(得分:43)
您可以按照以下方式删除警告:
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类文件时抱怨,但它仍然做得很好。
答案 1 :(得分:20)
顺便说一下,关闭警告的设置是在“代码样式”下的Java错误/警告页面中,并且被称为:
访问封闭类型的不可访问成员
答案 2 :(得分:9)
您无法从WeirdInnerClassJavaWarning实例化InnerClass。它是私有的,JVM不会让你,但Java语言(出于某种原因)会。
因此,javac会在InnerClass中创建一个只返回新的InnerClass()的附加方法,因此允许您从WeirdInnerClassJavaWarning创建InnerClass实例。
我认为你真的不需要摆脱它,因为性能下降会非常小。但是,如果你真的想要,你可以。
答案 3 :(得分:3)
我仍然不明白为什么使嵌套类受保护而不是私有是另一种解决“问题”的方法,但也许这是Eclipse的怪癖/错误
这不是Eclipse的怪癖/错误,只是Java的一个特性。 Java Language Specification, 8.8.9说:
...如果该类被声明为protected,则默认构造函数被隐式赋予访问修饰符protected ...
答案 4 :(得分:2)
为了帮助人们,如果您使用
中的问题中的原始类代码,可以获得以下内容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 {
}
答案 5 :(得分:0)
你应该能够通过使用默认范围而不是私有或受保护,即
来摆脱它static class InnerClass ...
值得注意的是,我将光标放在带有警告的代码行上并按下ctrl-1,Eclipse可能会自动为您修复此问题。