私の同僚は、いくつかの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()へのアクセスは、合成アクセサーメソッドによってエミュレートされます。視認性を上げるとパフォーマンスが向上します。
これは何を意味するのでしょうか? "private static class"を "protected static class"に変更すると警告が消えますが、これは意味がありません。
編集:私はようやく「正しい」修正を見つけました。ここでの実際の問題は、このネストされたプライベート静的クラスにパブリックコンストラクターがないことです。その1つのTweakは警告を削除しました:
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();
}
}
クラスをプライベートのネストされたクラスにしたいので(他のクラスがクラスにアクセスできないようにします(包含クラスのサブクラスを含む))、それを静的クラスにします。
ネストされたクラスをプライベートではなく保護することが「問題」を修正するもう1つの方法である理由はまだわかりませんが、おそらくそれはEclipseの奇妙なバグです。
(申し訳ありませんが、わかりやすくするために、InnerClassではなくNestedClassと名付けるべきでした。)
次のようにして警告を取り除くことができます:
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();
}
}
他の人が言ったように、Javaコンパイラーが作成する合成メソッドを使用しない限り、明示的なコンストラクターのないプライベートクラスは外部からインスタンス化できないため、Eclipseは不満を持っています。コードを取得する場合は、 、それを 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クラスファイルを逆コンパイルすると、complains)、それでも問題はありません。
ちなみに、警告をオフにする設定は、「コードスタイル」のJavaエラー/警告ページにあり、次のように呼び出されます。
囲んでいる型のアクセス不可能なメンバーへのアクセス
WeirdInnerClassJavaWarningからInnerClassをインスタンス化することはできません。それは非公開であり、JVMはあなたを許可しませんでしたが、Java言語が何らかの理由で)許可しました。
したがって、javacは新しいInnerClass()を返すだけのInnerClassのメソッドを作成し、WeirdInnerClassJavaWarningからInnerClassインスタンスを作成できるようにします。
パフォーマンスの低下が計り知れないほど小さいため、本当にそれを取り除く必要はないと思います。ただし、本当にしたい場合はできます。
ネストされたクラスをプライベートではなく保護することが「問題」を修正するもう1つの方法である理由はまだわかりませんが、おそらくそれはEclipseの奇妙なバグです
これはEclipseの癖/バグではなく、Javaの機能です。 Java言語仕様、8.8.9 は次のように述べています。
...クラスが保護されていると宣言されている場合、デフォルトのコンストラクタには暗黙的にアクセス修飾子が与えられます...
人々を助けるために、質問で元のクラスコードを使用した場合に得られるものは次のとおりです
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 {
}
プライベートまたは保護の代わりにデフォルトのスコープを使用して、それを取り除くことができるはずです。
static class InnerClass ...
また、警告が表示されているコード行にカーソルを置いてctrl-1を押すと、Eclipseが自動的にこれを修正できる場合があることに注意してください。