プライベートヘルパーメソッドは、静的である可能性がある場合、静的である必要があります。


205

インスタンス化するように設計されたクラスがあるとします。クラス内には、クラスメンバーへのアクセスを必要とせず、引数のみを操作して結果を返すプライベート "ヘルパー"メソッドがいくつかあります。

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne(member);
       total += computeMore(member);
       return total;         
   }

   private double computeOne(Something arg) { ... }
   private double computeMore(Something arg) {... } 
} 

特定する特別な理由はありますか computeOnecomputeMore静的メソッドとして、または特別な理由はありませんか?

問題がなくても静的である可能性がありますが、非静的のままにしておくのが最も簡単です。


3
:Javaでキーワードstaticを使用していないときも参照してくださいstackoverflow.com/questions/1766715/...
マーク・バトラー

回答:


174

私はそのようなヘルパーメソッドを好むprivate static; これにより、オブジェクトの状態は変更されないことが読者に明確になります。私のIDEは静的メソッドの呼び出しもイタリック体で表示するので、シグネチャを見なくてもメソッドが静的であることがわかります。


2
私のお気に入りのスレッドの1つです。NetBeansを使用しており、イタリックフォントを使用した静的メソッド呼び出しを示しています。
skiabox 2012年

2
通常、これらのヘルパーメソッドprotected staticは、同じパッケージのテストクラスで非常に簡単にテストできるように宣言します。
ジェームズ

2
@Jamesまたは単にstatic(テストのためだけに必要な場合)。
mrod

3
「オブジェクトの状態は変更しません」-プライベートメソッドと区別する方法の完全な説明。
HopeKing 2017年

110

静的メソッドはアクセスできないため、バイトコードがわずかに小さくなる可能性があります。 this。速度に違いはないと思います(もしそうなら、おそらく全体として違いを出すには小さすぎるでしょう)。

私はそれらを静的にするつもりです。しかし、それは私だけです。


編集:この回答は、おそらくバイトコードサイズに関する根拠のないアサーションのために、投票を続けています。実際にテストを実行します。

class TestBytecodeSize {
    private void doSomething(int arg) { }
    private static void doSomethingStatic(int arg) { }
    public static void main(String[] args) {
        // do it twice both ways
        doSomethingStatic(0);
        doSomethingStatic(0);
        TestBytecodeSize t = new TestBytecodeSize();
        t.doSomething(0);
        t.doSomething(0);
    }
}

バイトコード(で取得javap -c -private TestBytecodeSize):

Compiled from "TestBytecodeSize.java"
class TestBytecodeSize extends java.lang.Object{
TestBytecodeSize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

private void doSomething(int);
  Code:
   0:   return

private static void doSomethingStatic(int);
  Code:
   0:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   invokestatic    #2; //Method doSomethingStatic:(I)V
   4:   iconst_0
   5:   invokestatic    #2; //Method doSomethingStatic:(I)V
   8:   new     #3; //class TestBytecodeSize
   11:  dup
   12:  invokespecial   #4; //Method "<init>":()V
   15:  astore_1
   16:  aload_1
   17:  iconst_0
   18:  invokespecial   #5; //Method doSomething:(I)V
   21:  aload_1
   22:  iconst_0
   23:  invokespecial   #5; //Method doSomething:(I)V
   26:  return

}

静的メソッドを呼び出すには、2つのバイトコード(byteops?)が必要ですiconst_0(引数用)およびinvokestatic
非静的メソッドを呼び出すには、aload_1TestBytecodeSizeオブジェクトの場合は)、iconst_0(引数の場合は)、およびの3つが必要invokespecialです。(これらがプライベートメソッドでなかった場合、それはのinvokevirtual代わりにあったことに注意してinvokespecialください。JLS§7.7メソッドの呼び出しを参照してください。。)

さて、先ほど言ったように、invokestaticバイトコードが1つ少なくて済むという事実を除いて、これら2つのパフォーマンスに大きな違いがあるとは思いません。invokestaticそしてinvokespecialわずかに速くよりもする必要があります両方invokevirtual、彼らは両方の使用の静的、動的の代わりに結合が、どちらかが速く、他のよりある場合、私は考えを持っていないので、。良い参考文献も見つかりません。私が見つけることができる最も近いものは、この1997年のJavaWorldの記事です。

これらの命令によって呼び出されるメソッドは静的にバインドされているため、最も速い命令はinvokespecialandになる可能性が最も高くなりますinvokestatic。JVMがこれらの命令のシンボリック参照を解決して直接参照に置き換えると、その直接参照には実際のバイトコードへのポインタが含まれる可能性があります。

しかし、1997年以降、多くの変化がありました。

結論として...私はまだ私が以前言ったことに固執していると思います。速度はせいぜいマイクロ最適化であるため、速度を優先して選択する必要はありません。


非常に簡単な答えのように見えるものに対するこれらすべての否定的な投票。真実、正義のために+1 ....
スティーブB.

ありがとう。(-3のときに削除してバッジを取得することはできますが、:D)
マイケルマイヤーズ

2
JITコンパイラーはとにかくインライン化して最適化するため、バイトコード命令の量はそれがどれほど速くなるかとはほとんど関係ありません。
Esko Luontola、2009年

3
だから私は「速度に違いはないと思います(もしそうであれば、全体的に違いを出すには小さすぎるでしょう」と言いました。)
マイケルマイヤーズ

7
そのようなマイクロ最適化を行う前に、ホットスポットコンパイラの効果を検討する必要があります。
結論


18

答えは...場合によります。

memberが処理しているオブジェクトに固有のインスタンス変数である場合、なぜそれをパラメーターとして渡すのですか?

例えば:

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne();
       total += computeMore();
       return total;         
   }

   private double computeOne() { /* Process member here */ }
   private double computeMore() { /* Process member here */ } 
}

5
+1:例は悪いですが、静的にできるメソッドが多すぎると、コードの悪臭がします。ちなみに、静的メソッドは実際には関数であり、オブジェクト指向ではありません。それらは別のクラスのメソッドとして属しているか、この関数がメソッドとして属している可能性のあるクラスが欠落している可能性があります。
ビルK

11

静的ヘルパーメソッドを宣言する理由の1つは、クラスコンストラクターで「前」thisまたは「」で呼び出す必要がある場合ですsuper。例えば:

public class MyClass extends SomeOtherClass { 
    public MyClass(String arg) {
       super(recoverInt(arg));
    }

    private static int recoverInt(String arg) {
       return Integer.parseInt(arg.substring(arg.length() - 1));
    }
}

これは少し不自然な例ですがrecoverInt、この場合は明らかにインスタンスメソッドにはなりません。


コンストラクターでインスタンスメソッドを呼び出すことはできますが、super(...)またはthis(...)を使用して別のコンストラクターに委任している場合は、委任の後までインスタンスメソッドを呼び出すことができません(ただし、静的は指摘し
キップ

10

私はプライベート静的メソッドの明確な利点を本当に考えることはできません。そうは言っても、それらを非静的にすることにも特定の利点はありません。それは主に表示の問題です:オブジェクトを変更していないという事実を明確に強調するために、それらを静的にすることができます。

異なるアクセス権を持つメソッドの場合、2つの主な引数があると思います。

  • 静的メソッドは、オブジェクトのインスタンスを作成せずに呼び出すことができ、便利な場合があります
  • 静的メソッドは継承できません。これは、ポリモーフィズムが必要な場合に問題になる可能性があります(プライベートメソッドには関係ありません)。

その上、その違いはかなり小さく、インスタンスメソッドに渡されるこの追加のポインターが大きな違いをもたらすことを強く疑います。


4
静的にしないことの利点は、誰かがサブクラス化してメソッドの動作をオーバーライドできることです。
クリントミラー

7
メソッドをオーバーライドできないように、そのプライベートメソッドをクリントします。
Bhushan Bhangale 2009

正確に言うと、プライベートメソッドの場合、それほど大きな違いはないと思います。ただし、パブリックメソッドについては、私はあなたが言っていることに同意します。
Axelle Ziegler、

8

正解は次のとおりです。

フィールドから情報を取得せず、フィールドに情報を入力しないメソッドは、インスタンスメソッドである必要はありません。クラスまたはオブジェクトのフィールドを使用または変更しないメソッドは、静的メソッドである可能性もあります。


5

または[静的と宣言しない]特定の理由?

はい。

それらをインスタンスメソッドとして保持することで、後で別の実装を提供できるようになります。

ばかげて聞こえるかもしれませんが(実際には、これらのメソッドが50行のプログラムであなただけが使用している場合はそうです)、より大きなアプリケーションや他の人が使用するライブラリでは、より良い実装を選択することを決定するかもしれませんが、既存のコードを壊したい。

したがって、サブクラスを作成し、それを新しいバージョンで返します。メソッドはインスタンスメソッドとして宣言されているので、ポリモーフィズムにその働きを任せます。

さらに、コンストラクターをプライベートにして、同じ理由で静的なファクトリーメソッドを提供することもできます。

したがって、私の推奨は、それらをインスタンスメソッドとして保持し、可能であれば静的メソッドを使用しないことです。
言語が提供するダイナミズムを利用してください。

やや関連するビデオについてはこちらをご覧ください:優れたAPIを設計する方法とそれが重要な理由

「静的vsインスタンス」メソッドの説明とは直接関係ありませんが、API設計のいくつかの興味深い点に触れています。


1
完全に同意します。私は通常、この理由だけで静的およびプライベートを完全に避けようとします。他のほとんどの回答は要点を逃していると思います。
クリントミラー

22
私たちはプライベートヘルパーについて話しています。つまり、それらはクラスのパブリックAPIの一部ではありません。つまり、後で別の実装を提供したり、それらを非静的にしたり、その他の変更を加えたりすることを妨げるものは何もありません。
Jonik

Aaaahmm ...それは良い点ですJonik。それでも、良い習慣を作ることには十分な理由があります(もちろん主観的に言えば)
OscarRyz

2
まったくそう思わない。定義されているクラスを変更せずにプライベートメソッドを変更したいという正当な理由はありません。あなたが提案することを行う唯一の方法は、バイトコード操作によるものです。
Peter Lawrey、

2
あなたが提案することは、その方法がプライベートではない場合に意味を成しますが、それでも、想像上のニーズに基づいて設計するのではなく、現在のニーズに基づいて設計することをお勧めします。
Peter Lawrey、

5

静的メソッドを持つことに関する1つの問題は、オブジェクトを単体テストで使用するのをより困難にする可能性があることです。Mockitoは静的メソッドのモックを作成できず、メソッドのサブクラス実装を作成できません。


2
プライベートメソッドのテストは記述しないでください。こちらをご覧ください。静的かどうかに関係なく、プライベートメソッドをテストする必要はありません。
BW

@BWそれは非常に主観的なことです。プライベートメソッドをテストする正当な理由はたくさんあります。
ruohola

4

メソッドが基本的に単なる予測可能な状態情報を使用しないサブルーチンである場合、それを静的に宣言します。

これにより、他の静的メソッドまたはクラスの初期化で使用できます。

public class Example {
   //...

   //Only possible if computeOne is static
   public final static double COMPUTED_ONE = computeOne(new Something("1"));

   //...
}

3

静的/非静的の質問は、「本当にこのクラスのオブジェクトを使用する必要があるのでしょうか?」

では、異なるメソッド間でオブジェクトを渡していますか?オブジェクトには、静的メソッドのコンテキスト外で役立つ情報が含まれていますか?両方の方法を使用する場合、両方の方法を定義しない理由はありますか?

このジレンマに陥っている場合、メソッドに必要なすべてのデータが、オブジェクトの外のコードに浮かんでいるように見えます。これは、あなたの望むことですか?常にそのデータを常にオブジェクトに収集する方が簡単でしょうか?単一のモデルへのコミットについては、あいまいな場合があります。すべてを1つの方法で実行できる場合は、静的または非静的のいずれかを選択し、それを実行します。


3

このような場合の私の好みはcomputeOnecomputeMore静的メソッドを作成することです。理由:カプセル化。クラスの実装にアクセスできるコードが少ないほど、優れています。

あなたが与える例では、クラスの内部にアクセスする必要はなく、そうする必要もないことcomputeOnecomputeMore述べているので、なぜクラスのメンテナーが内部に干渉する機会を与えるべきでしょうか。


3

他のポスターが間違った情報を提供していると言っていることをいくつか明らかにしたいと思います。

まず、メソッドは静的であると宣言してもプライベートなので、このクラスの外部からはアクセスできません。次に、これらはプライベートであるため、サブクラスでオーバーライドすることもできないため、静的または非静的で違いはありません。3番目に、非静的プライベートメソッドは、クラスのコンストラクターからも呼び出すことができます。静的である必要はありません。

次に、プライベートヘルパーメソッドを静的または非静的として定義する必要があるかどうかについて質問します。プライベートメソッドを静的としてマークすると、このメソッドはステートレスであることを示すので、コーディング時にこのルールにも従うので、スティーブの答えを使用します。


しかし、私の例やChris Marshallの例のように、静的メソッドのみを呼び出すことができる場所があります
Kip

はいキップあなたとクリスの答えは正しいです。正解なのでコメントしていません。私は間違った答えについてだけ話しました。
Bhushan Bhangale 2009

3

経験から、そのようなプライベートメソッドは非常に普遍的で再利用可能である傾向があると私は述べます。

最初にすべきことは、メソッドが現在のクラスコンテキストの外で役立つかどうかを質問することです。もしそうなら、私は誰もが提案することを正確に行い、このメソッドをいくつかのutilsクラスに静的として抽出します。誰かがうまくいけば、まったく同じことをする新しいメソッドを実装する前にチェックします。

このような一般的に使用されるプライベートメソッドは、各開発者が使用する必要のある場所で独自に再発明するため、プロジェクトでのコード複製の大きな部分の原因となります。したがって、そのような方法を一元化することが1つの方法です。


2

より具体的には、あなたが与えた例では、これらのメソッドを定義する目的は、機能(それらプライベートとして定義されている)よりも、コードを明確にするためのものです。その場合、staticの目的はクラスの機能を公開することなので、staticを使用しても実際には何も起こりません。


他の多くの答えの下に埋もれているこの小さな答えは、本当に問題の本質に触れています。クラスレベルの機能とオブジェクトレベルの機能です。
eljenso

ありがとう、エル、本当に感謝しています。少し投票しても
構い

私がコメントを書いたときに私はそれに+1を与えました。
eljenso

1
同意しません。コードの明快さは、プライベートメソッドにとっても重要です。それはそれほど重要ではないかもしれませんが、それでも努力する必要があります。
LegendLength 2009年

1

1つの理由は、他のすべての条件が等しい場合、静的メソッドの呼び出しが高速になることです。静的メソッドは仮想にすることはできず、暗黙的なthis参照を使用しません。


以下の私の回答を参照してください(既に-3になってから分析を追加したため、あまりわかりません)。
マイケルマイヤーズ

1

多くの人が言ったように、それを静的なものにしてください!これが私が従うおおまかな規則です。メソッドが単なる数学関数、つまりステートレスであると考える場合、インスタンス変数(=>メソッドに青い色の変数がない[eclipse]を含まない)と結果メソッドは 'n'回の呼び出しで同じになります(もちろん、同じパラメーターで)、そのメソッドをSTATICとしてマークします。

このメソッドが他のクラスに役立つと思われる場合は、Utilクラスに移動します。そうでない場合は、メソッドを同じクラスのプライベートとして配置します。(アクセシビリティの最小化)


1

オフトピック:ヘルパーメソッドは、静的メソッドのみが含まれるスタンドアロンユーティリティ/ヘルパークラスに保持します。

使用時にヘルパーメソッドを使用することの問題(「同じクラス」を参照)は、将来、誰かが自分の無関係なヘルパーメソッドを同じ場所に投稿することを選択する可能性があることです


-1:SOはメッセージングフォーラムではありません。あなたは実際に適切な質問をすることでより上手になります。
Stu Thompson

1
私はそれらが静的なものとしてバインド/関連しているクラスと一緒にヘルパーメソッドを用意したいと思います。さらに、外部で使用する必要がある場合は、一部を公開することができます。そうすれば、公開して集中的に使用することが想定されている場合に、そのクラスのAPIを維持しやすくなります。
Ivaylo Slavov、2011年

1
class Whatever {

    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        //initialization code goes here
    }
}

プライベート静的メソッドの利点は、クラス変数を再初期化する必要がある場合に、後で再利用できることです。


1
  1. static修飾子がないと、メソッドを(再)作成するときに簡単に実行できる追加の分析なしに、メソッドがステートレスであることを理解できません。

  2. 次に、「静的」修飾子は、他の人が役に立たないと思うかもしれない他のもののほかに、リファクタリングについてのアイデアを与えるかもしれません。たとえば、メソッドをユーティリティクラスに移動したり、メンバーメソッドに変換したりします。


0

ステートレスとしてフラグを立てるために、それらを静的として宣言します。

Javaにはエクスポートされないマイナーな操作のためのより良いメカニズムがないので、プライベートスタティックは許容できると思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.