Javaで匿名の内部クラスを静的にすることは可能ですか?


123

Javaでは、ネストされたクラスはどちらでもよいしstatic、そうでなくてもよい。それらがstaticである場合、それらには包含インスタンスのポインターへの参照が含まれていません(これらは内部クラスとも呼ばれなくなり、ネストされたクラスと呼ばれます)。

static参照が不要なときにネストされたクラスを作成し忘れると、ガベージコレクションやエスケープ分析で問題が発生する可能性があります。

匿名の内部クラスstaticも作成できますか?または、コンパイラはこれを自動的に判断しますか(サブクラスがないため、可能です)。

たとえば、匿名コンパレータを作成する場合、外部への参照はほとんど必要ありません。

  Collections.sort(list, new Comparator<String>(){
       int compare(String a, String b){
          return a.toUpperCase().compareTo(b.toUpperCase());
       }
  }

内部クラスを静的にするのを忘れたときの「ガベージコレクションまたはエスケープ分析」の問題は何ですか?これはパフォーマンスのみに関するものだと思いました...
TimBüthe2009

17
内部クラスインスタンスは、必要がない場合でも、外部インスタンスへの参照を維持します。これにより、ガベージコレクションが行われなくなります。何かの軽量インスタンスを作成する(リソースの多い)ファクトリオブジェクトを描きます。ファクトリが処理を行った後(アプリケーションの起動時など)は破棄できますが、これは、作成したものがリンクされない場合にのみ機能します。
ティロ

私は、これが唯一の例であるが、それは定期的な1であることから、いることを言及する必要があります知っているCollections.sort(list, String.CASE_INSENSITIVE_ORDER)コレクションAPIが存在するためのJava 2以降の作品は、読んで...
ホルガー

回答:


138

いいえ、できません。また、コンパイラはそれを理解できません。FindBugs staticが暗黙のthis参照を使用しない場合、匿名内部クラスを名前付きネストクラスに変更することを常に提案するのはこのためです。

編集:トム・ホーティン-タックラインは、匿名クラスが静的コンテキスト(たとえば、mainメソッド内)で作成された場合、匿名クラスは実際にはそうであると述べていstaticます。しかし、JLSはこれに同意しません

匿名クラスは決してありませんabstract(8.1.1.1)。匿名クラスは常に内部クラスです(8.1.3)。それは決してありませんstatic(§8.1.1、§8.5.1)。匿名クラスは常に暗黙的ですfinal(§8.1.1.2)。

Roedy GreenのJava Glossary は、匿名クラスが静的コンテキストで許可されるという事実は実装依存であると述べています:

あなたのコードを管理している人たちを困惑させたいのなら、言語仕様が匿名クラスよりも決してではないとしても、wagはinitコードとメソッドjavac.exe内の匿名クラスを許可することを発見しました。もちろん、これらの匿名クラスは、オブジェクトのインスタンスフィールドにアクセスできません。これはお勧めしません。この機能はいつでもプルできます。staticstaticstatic

編集2: JLSは実際に静的コンテキストを§15.9.2でより明示的にカバーしています:

してみましょうCがインスタンス化されるクラスである、としましょう、私はインスタンスが作成されていること。場合Cが内部クラスであり、その後、私は直ちに取り囲むインスタンスを有することができます。iのすぐ外側のインスタンス(§8.1.3)は、次のように決定されます。

  • Cの場合その後、匿名クラスは、次のとおりです。
    • クラスインスタンス作成式が静的コンテキスト(§8.1.3)で発生する場合、iはすぐに囲むインスタンスを持ちません。
    • それ以外の場合、iを直接囲むインスタンスはですthis

したがって、静的コンテキストの匿名クラスは、static技術的にはクラスではありませんが、囲んでいるクラスへの参照を保持しないという点で、ネストされたクラスとほぼ同じstaticです。


19
FindBugsの+1-すべてのJava開発者はこれをビルドに含める必要があります。
アンドリュー・ダフィー

13
これは非常に残念です。パフォーマンス上の理由から、これを避ければほとんど簡潔な構文になるのを避けたい場合があるためです。
ティロ

2
JLS 3rd Edは、静的コンテキストの内部クラスのケースを扱います。これらはJLSの意味では静的ではありませんが、質問で与えられた意味では静的です。
トム・ホーティン-

6
次に、実装に依存する例を示します。このコードtrue、javac(sun-jdk-1.7.0_10)とfalseEclipseコンパイラを使用して出力します。
Paul Bellora

1
@MichaelMyers「this」参照を使用せずに匿名インナーを実行することを警告するFindBugsをシミュレートしようとしましたが、何も起こりません。回答の冒頭で述べたように、FindBugsがどのように警告するかを示すことができますか?リンクを貼り付けるか、何でもします。
Thufir Hawat、2015年

15

やや。静的メソッドで作成された匿名の内部クラスは、外部thisのソースがないため、明らかに静的です。

静的コンテキストの内部クラスと静的ネストされたクラスの間にはいくつかの技術的な違いがあります。興味があれば、JLS 3rd Edを読んでください。


実際、私はそれを取り戻しました。JLSは同意しません。java.sun.com/docs/books/jls/third%5Fedition/html/…:「匿名クラスは常に内部クラスであり、決して静的ではありません。」
マイケルマイヤーズ

1
問題のそれとは異なる意味で静的。
トム・ホーティン-

1
私は少し説明を追加しました。
トムホーティン-タックライン2009

15

ここの命名法には少し混乱があると思いますが、それは確かにばかげていて混乱しています。

それらを何と呼ぶにせよ、これらのパターン(および異なる可視性を持ついくつかのバリエーション)はすべて、可能な通常の正当なJavaです。

public class MyClass {
  class MyClassInside {
  }
}

public class MyClass {
  public static class MyClassInside {
  }
}

public class MyClass {
  public void method() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

public class MyClass {
  public static void myStaticMethod() {
    JComponent jc = new JComponent() {
      ...
    }
  }
}

これらは言語仕様で用意されています(本当に気になる場合は、静的メソッド内のセクションについては、セクション15.9.5.1を参照してください)。

しかし、この引用は明らかに間違っています:

javac.exeは、静的なinitコードおよび静的メソッド内の匿名クラスを許可します。ただし、言語仕様によると、匿名クラスは静的ではありません。

私は引用された著者が静的キーワードを静的コンテキストと混同していると思います。(確かに、JLSもこの点で少し混乱しています。)

正直なところ、上記のパターンはすべて問題ありません(「ネスト」、「内部」、「匿名」と呼ぶものは何でも...)。実際、Javaの次のリリースでは、この機能を突然削除する予定はありません。正直なところ!


2
「確かに、JLSもこの点で少し混乱しています。」正解です。実装に依存していると言うのは奇妙に聞こえますが、以前にJava用語集で明らかなエラーを見た覚えはありません。これからは、一粒の塩で飲みます。
マイケルマイヤーズ

2
実際には、どのパターンについても話していません。匿名のネストされたクラスは静的であることを意味します。すなわち間で「静的」を追加newし、JComponentあなたの第三の例では。
Timmmm

元の質問に説明を追加して、何が必要かを示しました。
Timmmm 2012

@ MichaelMyers、JLSのディクテーションは常に解釈する必要があります。
Pacerier


0

匿名の内部クラスは静的ではありません(静的メソッドまたは非final静的フィールドを宣言できません)が、静的コンテキスト(静的メソッドまたは静的フィールド)で定義されている場合、それらはできないという意味で静的として動作します包含クラスの非静的(つまり、インスタンス)メンバーにアクセスする(静的コンテキストの他のすべてと同様)


-3

静的メソッド内でそれらを呼び出すことにより、匿名内部クラスを静的にすることに注意してください。

これは実際には参照を削除しません。これをテストするには、匿名クラスをシリアル化しようとし、それを囲むクラスをシリアル化可能にしないようにします。


5
-1:静的メソッド内で匿名クラスを作成すると、実際には外部クラスへの参照削除されます。これをテストするには、匿名クラスをシリアル化しようとし、それを囲むクラスをシリアル化可能にしないようにします。(私はちょうどしました。)
クリスチャンセムラウ2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.