97

私は最近Eclipseで警告を調べていて、これに出くわしました。

静的警告

メソッドを静的として宣言できる場合は、コンパイラに警告が表示されます。

[編集] Eclipseヘルプ内の正確な引用、プライベートとファイナルに重点を置いて:

有効にすると、コンパイラーは、プライベートまたはファイナルで静的メンバーのみを参照するメソッドに対してエラーまたは警告を発行します。

はい、オフにできることはわかっていますが、オンにする理由を知りたいですか?

可能なすべてのメソッドを静的として宣言するのが良いのはなぜですか?

これにより、パフォーマンス上のメリットはありますか?(モバイルドメイン内)

メソッドを静的として指摘すると、インスタンス変数を使用しないため、utilsスタイルクラスに移動できることを示していると思いますか?

一日の終わりに、これを「無視」をオフにする必要がありますか、それとも100以上の警告を修正する必要がありますか?

コンパイラはとにかくこれらのメソッドをインライン化するだけなので、これはコードを汚す単なる余分なキーワードだと思いますか?(最終的に実行できるすべての変数を宣言するわけではありませんが、宣言することはできます)。

4

9 に答える 9

140

メソッドを作成するときはいつでも、特定のスコープでコントラクトを履行します。スコープが狭いほど、バグを作成する可能性は低くなります。

メソッドが静的である場合、非静的メンバーにアクセスすることはできません。したがって、スコープは狭くなります。したがって、コントラクトを実行するために非静的メンバーを必要とせず、(サブクラスでも)必要としない場合は、なぜこれらのフィールドへのアクセスをメソッドに許可するのでしょうか。この場合にメソッドを宣言するstaticと、コンパイラは、使用する予定のないメンバーを使用していないことを確認できます。

さらに、コードを読む人々が契約の性質を理解するのに役立ちます。

staticそのため、実際に静的コントラクトを実装しているときにメソッドを宣言することをお勧めします。

場合によっては、メソッドはクラスのインスタンスに関連する何かを意味するだけであり、その実装が実際には非静的フィールドまたはインスタンスを使用しないことがあります。このような場合、メソッドにマークを付けることはありませんstatic

staticキーワードを使用しない場合の例:

  • 何もしない拡張フック(ただし、サブクラスのインスタンスデータで何かを行うことができます)
  • サブクラスでカスタマイズできるように意図された非常に単純なデフォルトの動作。
  • イベントハンドラーの実装:実装はイベントハンドラーのクラスによって異なりますが、イベントハンドラーインスタンスのプロパティは使用しません。
于 2012-06-28T07:49:00.667 に答える
17

ここには最適化の概念はありません。

staticメソッドは、staticメソッドが必要がないという理由だけで、メソッドがクラスを囲むインスタンスに依存しないことを明示的に宣言するためです。そのため、ドキュメントに記載されているように、Eclipseの警告は次のとおりです。

有効にすると、コンパイラーは、プライベートまたはファイナルで静的メンバーのみを参照するメソッドに対してエラーまたは警告を発行します。

インスタンス変数が不要で、メソッドがプライベート(外部から呼び出すことができない)またはfinal(オーバーライドできない)である場合、静的メソッドではなく通常のメソッドにする理由はありません。this静的メソッドは、それを使用して実行できる操作が少ないという理由だけで、本質的に安全です(インスタンスは必要なく、暗黙のオブジェクトもありません)。

于 2012-06-28T07:51:52.730 に答える
7

パフォーマンスに関する情報はありませんが、コードがタイプに基づいて動的ディスパッチを実行する必要がないため、せいぜいわずかに優れていると思います。

ただし、静的メソッドへのリファクタリングに対するはるかに強力な議論は、現在静的メソッドを使用することは悪い習慣と見なされているということです。静的メソッド/変数はオブジェクト指向言語にうまく統合されておらず、適切にテストするのも困難です。これが、一部の新しい言語が静的メソッド/変数の概念を完全に放棄するか、OOでより適切に機能する方法で言語に内部化しようとする理由です(例:Scalaのオブジェクト)。

ほとんどの場合、入力としてパラメーターのみを使用し、それを使用して出力を生成する関数(ユーティリティ/ヘルパー関数など)を実装するには、静的メソッドが必要です。現代語には、それを可能にするファーストクラスの関数の概念があります。必要ありません。Java 8にはラムダ式が統合されるため、すでにこの方向に進んでいます。

于 2012-06-28T07:53:56.953 に答える
3

1.宣言方法staticわずかなパフォーマンス上の利点がありますが、さらに便利なのは、オブジェクトインスタンスを手元に持たずに使用できることです(たとえば、ファクトリメソッドやシングルトンの取得について考えてみてください)。また、メソッドの性質を伝えるという文書化の目的も果たします。この文書化の目的は、コードの読者とAPIのユーザーにメソッドの性質についての即時のヒントを提供し、元のプログラマーの思考のツールとしても機能するため、無視してはなりません。また、あなたはまっすぐに考えて、より良い品質のコードを生成します(私は私の個人的な経験に基づいていると思いますが、人々は異なります)。たとえば、論理的であるため、型で動作するメソッドと型のインスタンスで動作するメソッドを区別することが望ましいです(によって指摘されているように)C#の質問に対するコメントのJon Skeet)。

メソッドのさらに別のユースケースstaticは、手続き型プログラミングインターフェイスを模倣することです。java.lang.System.println()クラスとその中のメソッドと属性について考えてください。このクラスjava.lang.Systemは、インスタンス化可能なオブジェクトではなく、グループ化された名前空間のように使用されます。

2. Eclipse(または他のプログラムされたまたは他の種類の-バイオコンポーザブルまたは非バイオコンポーザブル-エンティティ)は、どのメソッドが静的として宣言できるかを確実に知ることができますか?基本クラスがインスタンス変数にアクセスしたり、非静的メソッドを呼び出したりしていない場合でも、継承のメカニズムによって状況が変わる可能性があります。サブクラスを継承してメソッドをオーバーライドできない場合にのみ、メソッドが実際に宣言できることを100%確実に主張できますstatic。メソッドをオーバーライドすることは、次の2つの場合に正確に不可能です。

  1. private(サブクラスはそれを直接使用できず、原則としてそれについてさえ知りません)、または
  2. final(サブクラスからアクセスできる場合でも、インスタンスデータまたは関数を参照するようにメソッドを変更する方法はありません)。

したがって、Eclipseオプションのロジック。

3.元の投稿者は、「メソッドを静的として指摘しているので、インスタンス変数を使用していないため、utilsスタイルクラスに移動できることを示していると思いますか?」と質問します。これは非常に良い点です。この種の設計変更は、警告によって示される場合があります。

Eclipseを使用し、Javaでプログラミングする場合、個人的に必ず有効にするオプションとして非常に便利です。

于 2012-07-04T05:21:42.837 に答える
1

メソッドの範囲がどのように変化するかについては、Samuelの回答を参照してください。これがメソッドを静的にする主な側面だと思います。

パフォーマンスについても質問しました。

静的メソッドの呼び出しでは、パラメーターとして暗黙の「this」参照を必要としないため、パフォーマンスがわずかに向上する可能性があります。

ただし、このパフォーマンスへの影響は非常に小さいです。したがって、それはすべてスコープに関するものです。

于 2012-06-28T07:56:31.023 に答える
1

Androidパフォーマンスガイドラインから:

仮想よりも静的を優先するオブジェクトのフィールドにアクセスする必要がない場合は、メソッドを静的にします。呼び出しは約15%〜20%速くなります。メソッドのシグネチャから、メソッドを呼び出してもオブジェクトの状態を変更できないことがわかるため、これも良い習慣です。

http://developer.android.com/training/articles/perf-tips.html#PreferStatic

于 2013-07-17T15:12:47.177 に答える
0

さて、Eclipseのドキュメントには問題の警告について書かれています:

メソッドは静的にすることができます

有効にすると、コンパイラは、プライベートまたはファイナルで静的メンバーのみを参照するメソッドに対してエラーまたは警告を発行します。

私はそれがほとんどすべてを言っていると思います。メソッドがプライベートでfinalであり、静的メンバーのみを参照している場合、問題のメソッドは静的と宣言される可能性があります。これにより、そこから静的コンテンツにのみアクセスすることを意図していることが明らかになります。

正直なところ、その背後に他の不思議な理由はないと思います。

于 2012-07-03T19:53:52.603 に答える
0

速度の違いのためにいくつかの数字が欠けていました。だから私はそれらをベンチマークしようとしましたが、それほど簡単ではないことがわかりました:Javaループはいくつかの実行/ JITの障害の後に遅くなりますか?

私はついにキャリパーを使用しました。結果は手作業でテストを実行した場合と同じです。

静的/動的呼び出しに測定可能な違いはありません。少なくともLinux/AMD64/Java7ではそうではありません。

キャリパーの結果は次のとおりです:https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName、scenario.vmSpec.options.CMSLargeCoalSurplusPercent、scenario.vmSpec.options。 CMSLargeSplitSurplusPercent、scenario.vmSpec.options.CMSSmallCoalSurplusPercent、scenario.vmSpec.options.CMSSmallSplitSurplusPercent、scenario.vmSpec.options.FLSLargestBlockCoalesceProximity、scenario.vmSpec.options.G1ConcMarkStepDurationM

そして私自身の結果は次のとおりです。

Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms

キャリパーテストクラスは次のとおりです。

public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {

    public static void main( String [] args ){

        CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
    }

    public int timeAddDynamic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addDynamic( 1, i );
        }
        return r;
    }

    public int timeAddStatic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addStatic( 1, i );
        }
        return r;
    }

    public int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

そして、私自身のテストクラスは次のとおりです。

public class TestPerformanceOfStaticVsDynamicCalls {

    private static final int RUNS = 1_000_000_000;

    public static void main( String [] args ) throws Exception{

        new TestPerformanceOfStaticVsDynamicCalls().run();
    }

    private void run(){

        int r=0;
        long start, end;

        for( int loop = 0; loop<10; loop++ ){

            // Benchmark

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addStatic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Static: " + ( end - start ) + " ms" );

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addDynamic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Dynamic: " + ( end - start ) + " ms" );

            // Do something with r to keep compiler happy
            System.out.println( r );

        }

    }

    private int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}
于 2014-07-22T16:07:05.203 に答える
-2

静的として宣言できるメソッドは、インスタンス化を必要としないメソッドです。

public class MyClass
{
    public static string InvertText(string text)
    {
        return text.Invert();
    }
}

その後、そのクラスをインスタンス化せずに、他のクラスで呼び出すことができます。

public class MyClassTwo
{
    public void DoSomething()
    {
        var text = "hello world";
        Console.Write(MyClass.InvertText(text));
    }
}

...しかし、それはおそらくあなたがすでに知っていることです。メソッドがインスタンス変数を使用しないことをより明確にすることを除いて、それ自体は実際の利点を提供しません。

つまり、完全にオフにするだけで最も安全になります。他のクラスでメソッドを使用しないことがわかっている場合(この場合はプライベートにする必要があります)、静的である必要はまったくありません。

于 2012-06-28T07:52:43.813 に答える