7

アプリケーションにデータ クラスがあります。私のアプリケーションがパブリック API として使用されることは決してなく、プロジェクト内でコードを開発するのは私だけです。

プロセッサとメモリの電力を可能な限り節約しようとしています。

ゲッターを使用する必要がないように、データ クラスのデータ メンバーを public/protected/default 保護にするのは悪い考えですか? ゲッターを使用すると、わずかに多くのメモリとスタックなどの作成が必要になります...これは必要ではないと思います。ゲッターを使用する唯一の理由は保護/プライバシーのためですが、私が唯一のコーダーであり、他の誰も私の API を使用しない場合、ゲッターを使用しないのは悪い考えですか?

これがばかげているかどうか教えてください。

4

28 に答える 28

24

パフォーマンス/メモリの最適化のためにゲッター/セッターを置き換えている場合は、間違ったアプローチを取っています。これらが、アプリケーションの実行速度が遅くなったり、メモリを大量に使用したりする理由になることはほとんどありません。

最適化の最大の罪は、必要があることに気付く前にそれを行うことです。最も多くの時間/メモリが浪費されている場所を示す実際の情報がある場合にのみ最適化し、それを最適化することに時間を費やしてください。この背後にある考え方は、全体の実行時間の 5% しか貢献しないコードを 20% 削減するよりも、合計実行時間の 80% を占めるコードを 5% 削減する方が、より多くの利益を得られるということです。総実行時間。(メモリも同様です。)

また、いくつかのプロパティ(単純なプロパティなど)に直接アクセスできる一方で、他のプロパティ(より複雑な派生プロパティ、または基になる型) にはゲッター/セッターがあります。そのため、アクセス スタイルが混在することになり、保守性が低下します。

于 2009-02-16T22:21:04.687 に答える
11

最適化のためにメンバーを公開することはお勧めできません。他の方もおっしゃっていますが、ほとんど影響はありません。ただし、オブジェクトがほとんど動作のない単純なデータ構造である場合は、そのように記述しても問題ありません。パフォーマンスではなく、シンプルさと読みやすさのためにそれを行っている限り。

于 2009-02-16T22:23:11.717 に答える
8

いずれにせよ、単純なゲッターとセッターがインライン化される可能性は十分にありますが、パブリック フィールドを使用すると、コントラクト (API) と実装の区別が失われます。これが使用する API に過ぎない場合でも、IMO を疎結合にしておくことをお勧めします。

于 2009-02-16T22:15:05.403 に答える
4

あらゆる最適化と同様に、マイナス面を正当化する利点があるかどうかを確認するために、前後に測定してください。

コードのパフォーマンスに目立った違いはないことがわかると思います (ただし、自分で試してみてください)。JVM は、頻繁に使用されるゲッターとセッターをインライン化します。

プロファイラーを使用して、アプリケーション内の実際の hotpsot を見つけます。証拠のない最適化は当て推量にすぎません。

于 2009-02-16T22:22:54.870 に答える
4

Python の人々は getter を使用しておらず、地獄に落ちているわけでもありません。

ゲッター/セッターは、クラスの一部を Java の単純なイントロスペクションに公開する方法です。Java Bean 仕様は、どの属性が重要であるかを判断する方法として、パブリックの getter と setter を持つことに依存しています。

Bean を要求/生成/使用するものには不可欠ですが、オブジェクト指向プログラミングや Java プログラミングの必須機能ではありません。これは Bean 仕様の一部にすぎず、Bean のようなものに参加したいすべてのクラスに必要です。

パブリック属性は問題ありません。それらは単純で直接的で明白です。

于 2009-02-16T22:15:14.793 に答える
3

この質問の逆は、より良い質問だと思います:

オブジェクトのメンバーを公開することは良い考えですか?

開発では、必要な最低限のアクセシビリティ レベルを使用するという原則に基づいてアプローチすることをお勧めします。つまり、必要なだけのデータのみを公開します。この原則を一般的に適用すると、必要な分だけ共有するというより実践的なものになります。

そうは言っても、なぜこれを行うのですか?

于 2009-02-17T00:19:12.623 に答える
3

これは少し異端的ですが、他の誰もあなたのクラスを使用しないことがわかっている場合は、そのようなことは飛ばしてよいことに同意します。APIの背後に隠されていても、再利用される可能性のあるコードでは実行しませんが、あなたの場合はかなり安全だと思われます.

于 2009-02-16T22:11:38.530 に答える
2

パブリック API に何かを入れると、それが固定されていることを考慮してください。名前を変更したり、タイプを変更したり、保存方法を変更したりすることはできません。

これをメソッドの背後に置いても、最新の VM でパフォーマンスが低下することはありません (過去 10 年間のほぼすべて)。

私の意見では、値を取得する方法を持つことで得られる柔軟性の方が重要です。

それらを公開することに決めた場合は、それらを最終としてマークし、それらが不変であることを確認してください。

公開クラス ポイント
{
    public final int x;
    public final int y;

    public Point(final int xVal, final int yVal)
    {
        x = xVal;
        y = yVal;
    }
}

編集:

パブリック API とは、クラス自体が他の開発者向けに公開された API の一部になるという意味ではなく、パブリックな変数を意味します。公開することで、後で問題を引き起こす可能性があります (他の開発者がアクセスできる「本当の」公開 API である場合、更新をリリースするときに他の人のコードを壊したくない限り、文字通り石に設定されます)。

于 2009-02-16T22:24:31.057 に答える
2

使用されるメモリの量はごくわずかだと確信しています。JVM は、実稼働用にビルドする場合、実行時の実装に応じて呼び出しをインライン化するように最適化することさえあります。自分で開発している場合でも、バグを追跡するのが難しい場合は、getter/setter にブレークポイントを設定して、いつ値を変更するかを正確に確認できるため、役立つ場合があります。ほとんどの最新の IDE にはコードを自動的に生成する機能があるため、コードを記述する必要もありません。

于 2009-02-16T22:13:09.400 に答える
2

早すぎる最適化の問題はすべて、以前の回答で説明されています。

Java では、次のように public メンバーのみでクラスを定義することにより、C の構造体を模倣できることに言及する価値があると思いました。

public class DataClass {
    public int a;
    public String b;
    public char c;
}

これらのパブリック メンバーを参照することによってのみアクセス (取得および設定) されます。

このイディオムは、特定のシナリオでは完全に受け入れられます。

于 2009-02-16T22:40:18.290 に答える
2

ゲッターとセッターは、保護/プライバシーのためだけではありません。主な用途は、基になるデータを公開する方法を変更することです。

たとえば、asp.net c# では、コントロールの visible プロパティには次のようなものがあります。

private bool visible = true;

public bool Visible
{
    get
    {
        return visible && Parent.Visible;
    }
    set
    {
        visible = value;
    }
}

外部プロパティ (アクセサー/ミューテーター) は、基になる変数とは異なる意味を持ちます。また、最初に上記の機能がなくても、単純な get/set があれば、後で簡単に追加できるものになります。

パフォーマンス ポイントについては、プロセッサとメモリのすべてのオンスを節約できます。これが顕著な影響を与える場合は、おそらく別の言語に目を向けたほうがよいでしょう。

于 2009-02-16T22:45:56.577 に答える
2

プロパティの代わりにパブリック フィールドがあればと思ったことは一度もありませんが、プロパティが欲しくてパブリック フィールドがあった回数は数えきれません。最終的には、その中にロジックが必要になります。

于 2009-02-16T23:04:08.763 に答える
1

IMHO、その性質上、データを受動的に保持することを目的としており、API ユーザーの観点からその意味を完全に変更することなく、より複雑なことを行うことはできないプロパティの場合、ゲッターとセッターは不必要なボイラープレートです。プロパティが、その性質上、C 構造体と同様に使用されるクラスなどの単なるデータ ホルダーである場合は、愚かなことを公開します。より一般的に言うと、ベスト プラクティスがベスト プラクティスである理由を考えずに熱心に適用すると、簡単に時間の無駄になり、最悪のプラクティスにさえなる可能性があります。一体、goto でさえ間違いなく正当化されることがあります。

于 2009-02-16T22:28:50.330 に答える
1

パフォーマンスが優先される場合は、Java 仮想マシンの選択と、それによるプログラムの実行方法を検討する必要があります。Sun のデスクトップ Java は、Java バイト コードのプロファイリングとマシン コードへのコンパイルに多くの時間を費やします。その結果、プログラムは非常に高速に実行される可能性がありますが、多くのメモリを使用します。

HotSpot ベースの JVM を使用したい場合は、それを支援するためのすべてのトリックを調べる必要があります。通常、ゲッターとセッターはインライン化され (つまり、サブルーチンの呼び出しではなく、マシン コードで直接置き換えられます)、定数は折り畳まれます。小さな範囲の switch ステートメントは通常、ジャンプ テーブルに変換されます。

通常、コードの大部分の記述には「頭から腕の下」の方法がうまく機能することがわかっています。次に、実行中のコードをプロファイリングしてボトルネックを見つけます。たとえば、StringBuffers は多くの点で高速ですが、deleteCharAt(0) はその 1 つではありません。文字列バッファで削除する代わりに、文字列に対して単純な反復を使用するように書き直したところ、驚くべき結果が得られました。あなたもおそらく、最大のメリットはアルゴリズムにあることに気付くでしょう。小さな近道ではありません。

C の世界では、もはや人間がコンパイラーを出し抜くことはほとんどできません。Java の世界では、人間は単純な Java を書くことで HotSpot を助けることができます。

于 2009-02-17T22:57:06.273 に答える
1

ばかげているわけではありませんが、おそらく良い考えでもないと思います。

私はその誘惑を理解しています...他の誰もコードを使用していない場合は、心配する必要はありません。しかし、これは実際に起こっていることと一致しないことが何度もわかります...思ったよりも多くの場所でそれを使用することになるか、プロジェクトが予想よりも大きくなるか、誰かが単にそれを手に入れて、それが有用だと思う...永続的または公開することを決して意図していなかったものは、そのようになる方法を持っています.

プロセッサのパワーとメモリにそれほど厳しい制限はありますか? 私はあなたの状況については知りませんが(おそらく組み込みアプリですか?)、(過度に一般化された)ルールとして、データ構造、アルゴリズム、またはアーキテクチャの他の場所でリソースを探して、より良い改善を確認することをお勧めしますメモリまたは CPU。

于 2009-02-16T22:13:18.073 に答える
1

あなたのコードを読んだ人があなたの住んでいる場所を知っていて、連続殺人犯であるかのように常にコーディングしてください。自分だけのコードを開発する場合でも、チームで開発するように (imo) やってみてください。このようにして、読みやすいベスト プラクティス コードの作成に慣れることができます。パフォーマンスのオーバーヘッドに関しては、メモリのすべてのビットと CPU のすべてのサイクルが本当に本当に必要な場合は、C などで行う方がよいかもしれません。

于 2009-02-16T22:16:37.583 に答える
1

使用の潜在的な欠点

public final タイプ 変数;

それ以外の

private final タイプ 変数;

public タイプ getvar () {return var ;}

(私が個人的に経験したことです)には以下が含まれます:

  • 基本クラスまたは将来のサブクラスで、表現を変更する必要がある可能性があります。

  • 公開された不変型フィールドと可変型フィールドを混在させることの潜在的な厄介さ。

  • public finalどのクラスが var を使用し、どのクラスがgetvarを使用するかを覚えておくのは面倒です。

  • 後でソースコードを見るかもしれない誰かに、この不一致を説明する手間。

試してみたにもかかわらず、それだけの価値があると自分に納得させることができませんでした.

于 2009-02-16T22:52:59.180 に答える
1

2 つの小さなクラスを作成し、それらをテストしました。

  • まず、プロトタイプとして単一のオブジェクトを作成しました。

  • 次に、それらすべてを格納するために 2,000,000 個の配列を作成しました。

  • 次に、ループを実行し、そこに新しいインスタンスを作成して、プロトタイプから値を取得しました。

それぞれを比較する秒単位の平均結果は次のとおりです。

WithGS  Without
1.1323  1.1116

Diff  = 0.0207 secs.

したがって、この場合、最初に最適化されていないソリューションを用意し、それ以上の要件が不要になったら、プロファイリングを続行する方がはるかに良いと思います。

コードは次のとおりです。

PersonGetSet.java


public class PersonGetSet {
    private String name;
    private boolean deceased;

    public void setName( String name ) {
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public void setDeceased( boolean deceased ) {
        this.deceased = deceased;
    }
    public boolean isDeceased() {
        return this.deceased;
    }

    public static void main( String [] args )  {
        PersonGetSet pb = new PersonGetSet();
        pb.setName( "name" );
        pb.setDeceased( true ) ;

        long start = System.currentTimeMillis();
        PersonGetSet [] array = new PersonGetSet[2000000];
        for( int i = 0 ; i < array.length; i++ ) {
            PersonGetSet personGs = new PersonGetSet();
            personGs.setName( pb.getName() );
            personGs.setDeceased( pb.isDeceased() );
            array[i] =  personGs;
        }
        System.out.println( "PersonGetSet took " + ( System.currentTimeMillis() - start ) + " ms. " );
    }
}


Person.java


public class Person {
    String name;
    boolean deceased;
    public static void main( String [] args )  {
        Person pb = new Person();
        pb.name=  "name" ;
        pb.deceased = true;

        long start = System.currentTimeMillis();
        Person [] array = new Person[2000000];
        for( int i = 0 ; i < array.length; i++ ) {
            Person simplePerson = new Person();
            simplePerson.name=  pb.name;
            simplePerson.deceased = pb.deceased;
            array[i] =  simplePerson;
        }
        System.out.println( "Person took " + ( System.currentTimeMillis() - start ) + " ms. " );
    }
}
于 2009-02-16T23:20:54.697 に答える
0

決して必要とならない機能的な設計(ゲッター/セッター)は、時期尚早の最適化と同じくらい悪いことです。これが本当にあなたの使用のためだけであるならば、それを公開しないでください、そしてそれからあなたが最も簡単であると信じるそれを構造化してください。

最適化やゲッターは、実際に必要な場合にのみ追加する必要があります。

于 2009-02-17T07:15:50.470 に答える
0

final 以外のフィールドを public にすることは常に悪い考えです。

後でイベント通知を追加したい場合はどうしますか?

後でサブクラス化して動作を変更したい場合はどうしますか?

フィールド間で強制したい制約がある場合はどうすればよいでしょうか?

TofuBeer は、final フィールドを持つ Point クラスを示しています。これで問題ありません。しかし、AWT の Point クラスは final を使用しないため、Java の初期段階で多くの悲しみが生じました。

私はいくつかの 3D コードを書いていて、x と y が変更されるたびに必要に応じて z を自動的に調整できるように Point をサブクラス化したいと考えていました。Point のフィールドは公開されているため、x または y がいつ変更されたかを知る方法はありません!

于 2009-02-17T13:13:43.980 に答える
0

このコードは自分で使用するためだけのものであるという議論は、非常に簡単に陥りやすい罠です。これは、ほとんどのコードに当てはまります。一般に公開されているビットは通常、非常に小さいものです。したがって、ほとんどのコードが私用であると仮定すると、なぜプライベート、保護、最終、const (C/C++) を使用する必要があるのか​​ -私が知っている復習的な質問ですが、要点が明確であることを願っています.

ここで見逃されているもう 1 つのことは、ロックです。メンバーに直接アクセスすると、オブジェクト全体またはメンバー レベルでのみこのコードをロックできます。そして、そのロックは、オブジェクト自体ではなく、コードを使用して制御されます。大丈夫かもしれませんが、そうではないかもしれません。

于 2009-02-22T02:43:21.177 に答える
0

パフォーマンスが重要な場合は、同じクラスでのみアクセスされる場合はフィールドをプライベートにするか、別のクラスでアクセスされる場合はパッケージをローカルにすることをお勧めします。内部/ネストされたクラスのプライベート フィールドを指定すると、コンパイラはアクセサ メソッドを追加/使用します (VM では、クラスが別のクラスのフィールドにアクセスすることは許可されていませんが、Java は許可されています)。

公開された可変フィールドを持つことは、私にとって設計上の問題を示唆しています。パフォーマンス クリティカルなコードを複数のパッケージに分割しても、パフォーマンス クリティカルなコードに必要な厳密なコーディングとは言えません。

不変フィールドがある場合、フィールドの動作が変更された場合に開発コストが高くなると予想される場合は、フィールドを公開しても問題ありません。実際、これによりコードがよりシンプル/理解しやすくなると思われる場合は、public immutable フィールドを使用することをお勧めします。

ただし、最優先事項はコードの読みやすさです。多くの場合、最も単純なコードも最高のパフォーマンスを発揮します。

于 2009-02-22T03:20:37.717 に答える
0

スタックの使用は非常に一時的であり、とにかく確実ではありません。とにかく、コンパイラが不要なオーバーヘッドを最適化するので、実際には何も得られないことに気付くかもしれません。

プライベートな非 API クラスがパブリック メンバーを使用することは必ずしも悪いことではありませんが、得られるものは非常に小さい (もしあったとしても) 私は気にしません。

于 2009-02-16T22:16:34.773 に答える
0

ゲッターはまったく必要ですか?つまり、クライアントがデータ値を取得して自分で作業を実行するのではなく、オブジェクトが作業を行うべきでしょうか?

OOP の重要な側面の 1 つは、ビットを引き出して自分で行うのではなく、オブジェクトに何かを行うように指示することです。例えば

double ret = myObj.calculateReturn()

対。

int v = myObj.getValue();
int ov = myObj.getOldValue();
double ret = (v-ov)/ov * 100; // do I work about dividing by zero etc.? 

私はよく見ます。多くの場合、ゲッター (およびおそらくセッター) が必要ですが、ゲッターを作成するときは、そのデータを公開する必要があるかどうか、またはオブジェクトがデータを完全に非表示にする必要があるかどうかを常に自問します。

于 2009-02-17T12:50:35.047 に答える
0

誰がコードを書き、誰がそれを使用するかという観点からは、それがあなたであろうと他の誰かであろうと関係ありません。それでもゲッターとセッターが必要になる場合があります。 API。

ただし、それが本当に単なるデータであり、クラスに関連付けられた動作が必要ない場合は、必ずメンバーを公開してください。

私にとっては、クラスに何らかの動作があるかどうか、または実装の詳細としてそのデータ メンバーの名前または型を変更する必要があるかどうかが本当に重要です。

プロセッサのパワーとメモリについて - 測定しましたか?

于 2009-02-16T22:17:46.783 に答える
0

私たちのチームでは、次のルールを使用しています。クラス フィールドによって表される状態が変更可能な場合は、常にそれを非公開にし、ミューテーターを提供します。ただし、それが不変である場合 (つまり、クラスのインスタンス化後に再割り当てされない場合)、次のように宣言できますpublic final [type] [field-name]-- アクセスしても安全です。

ここで「不変状態」とは、具体的にはフィールドが として宣言されていることを意味することに注意してくださいfinalpublic [immutable-type] [field-name]不変型のインスタンス自体は不変ですが、再割り当てを実行できる場所と混同しないでください。

Pls はまた、不変フィールドに対してもアクセサを使用する正当な理由がたくさんあることにも注意してください。たとえば、フィールドの読み取り時に何らかのアクション (セキュリティ チェックなど) を実行する必要がある場合などです。

于 2009-02-20T18:46:44.403 に答える
0

速度が重要な場合は、C または C++ で作成する価値があるかもしれません。

于 2009-02-16T23:01:47.193 に答える
0

一般的に: 何かを手動で最適化したい場合は、そのようなマイクロ最適化ではなく、アーキテクチャの改善を検討する必要があります。多くの場合、マイクロ最適化はツールによって自動的に実行できます。

Java の場合: 多くの最適化を実行できる ProGuard ツールがあります。ただし、最新の JVM (HotSpot や OpenJDK など) を使用する場合、JVM はこれらの最適化をジャストインタイムで実行できます。実行時間の長いアプリケーションがある場合、ProGuard はパフォーマンスに多少の影響を与える可能性があります。

于 2011-03-26T11:20:51.027 に答える