同じクラスの別のオブジェクトのプライベートフィールドにアクセスする


91
class Person 
{
   private BankAccount account;

   Person(BankAccount account)
   {
      this.account = account;
   }

   public Person someMethod(Person person)
   {
     //Why accessing private field is possible?

     BankAccount a = person.account;
   }
}

デザインを忘れてください。OOPは、プライベートオブジェクトがクラスに対してプライベートであることを指定していることを知っています。私の質問は、プライベートフィールドがオブジェクトレベルのアクセスではなくクラスレベルのアクセスを持つようにOOPが設計されたのはなぜですか?


5
OPは、「someMethod」に渡された「Person」オブジェクトを別個のオブジェクトと見なしているため、メソッドは「Person」クラス内にある場合でも、そのプライベートメンバーにアクセスできないようにする必要があると思います。
イニシアー2013年

1
一部の言語はこれを行いません(たとえば、Newspeak)。理由については、良い答えが得られない可能性があります。たまたま指定されたものから逆方向に機能する回答が得られます。
トムホーティン-タックライン2013年

someMethod有効ではありません。何も返しません。でなければなりませんvoid
Nicolas Barbulesco 2013

1
そうでない場合、コピーコンストラクターと代入演算子imoを作成するのは非常に困難です。
rozina 2014年

回答:


69

私もその答えに少し興味があります。

私が見つけた最も満足のいく答えは、ここにある別の投稿のArtemixからのものです(私はAClassの名前をPersonクラスに変更しています): なぜオブジェクトレベルではなくクラスレベルのアクセス修飾子があるのですか?

プライベート修飾子は、カプセル化の原則を適用します。

Personの実装は時間の経過とともに変化する可能性があるため、「外界」はPersonの内部プロセスに変更を加えるべきではないという考え方です(実装の違いを修正するには、外界全体を変更する必要があります。これはほぼ不可能です)。

Personのインスタンスが他のPersonインスタンスの内部にアクセスする場合、両方のインスタンスが常にPersonの実装の詳細を知っていることを確認できます。Personプロセスの内部のロジックが変更された場合、必要なのはPersonのコードを変更することだけです。

編集:Artemixの回答に投票してください。コピーして貼り付けているだけです。


4
これがおそらく理由です。しかし、これは悪い考えです。これは悪い習慣を助長します。Personクラス内ののフィールドにアクセスする開発者は、クラスPerson全体の実装を知る必要はありません。アクセサがどのような操作を行うかを知らなくても、アクセサを使用することをお勧めします。
Nicolas Barbulesco 2013

16
@NicolasBarbulesco答えに出された理由は正しいと思います。たとえばequals(Object)、Javaクラスにメソッドを実装して、Personオブジェクトとの別のインスタンスとの同等性をチェックするとしますPerson。2つのインスタンスが等しいかどうかを外部が確認できるようにすることもできますが、パブリックアクセサメソッドを使用して外部との同等性を確認するために必要なクラスのプライベートフィールドをすべて公開したくない場合があります。privateフィールドへのクラスレベルのアクセス権があると、そのようなパブリックメソッドを実装する必要なしにそのようなメソッドを実装できます。
Malte Skoruppa 2015年

1
@ MalteSkoruppa-これは良い例です(メソッドの実装equals)。
Nicolas Barbulesco 2015年

@ MalteSkoruppa-ただし、メソッドの実装は、equalsプライベートアクセサーを呼び出すことで実行できます。
Nicolas Barbulesco 2015年

@NicolasBarbulescoはい。もちろんですが、重要なのは、プライベートアクセサーを使用するか、メソッドを実装するためにプライベートフィールドに直接アクセスするかにかかわらず、privateクラスレベルのアクセスを許可する必要があるということです。アクセサーを使用することは一般的に良い習慣であることに同意しますが、この場合、それは主にコンテキストと個人的なスタイルの問題です。このDr.Dobbsの記事のJoshuaBloch in Effective Java(アイテム8)とTal Cohenはどちらも、実装方法について説明するときに、コードリストのプライベートフィールドに直接アクセスすることに注意してください。equals
Malte Skoruppa 2015年

17

Java言語仕様のセクション6.6.1を参照してください。アクセシビリティの決定

それは述べています

それ以外の場合、メンバーまたはコンストラクターが宣言privateされている場合、アクセスは、メンバーまたはコンストラクターの宣言を囲む最上位クラス(§7.6)の本体内で発生する場合にのみ許可されます。

詳細については、上のリンクをクリックしてください。つまり、答えは次のとおりです。JamesGoslingと他のJavaの作成者は、そのように決定したからです。


17

良い質問。オブジェクトレベルのアクセス修飾子は、カプセル化の原則をさらに強化するようです。

しかし、実際にはその逆です。例を見てみましょう。オブジェクトのプライベートメンバーにアクセスできない場合は、コンストラクターでオブジェクトをディープコピーするとします。次に、可能な唯一の方法は、すべてのプライベートメンバーにパブリックアクセサーを追加することです。これにより、オブジェクトがシステムの他のすべての部分に対してになります。

したがって、カプセル化は、世界の他のすべての地域に閉鎖されることを意味するものではありません。それはあなたが誰に開かれたいかについて選択的であることを意味します。


2
この回答は投票する必要があります!他の答えは「ルール」を言い換えるだけですが、これだけがルールの背後にある理由を明らかにし、要点を打ちます。
mzoz 2018年

4
しかし、オブジェクトがそれ自体のコピーを提供する責任を負うほうがよいのではないでしょうか。次に、オブジェクトのディープコピーが必要な場合は、同じクラスの別のオブジェクトであるか、別のクラスのオブジェクトであるかは関係ありませんo.deepCopy()。同じメカニズムであるかどうかは関係ありません。
ダートサイド

4

これが機能するのはclass Person、クラスが独自のタイプのクラス内を突くことが許可されているためです。これは、次のようなコピーコンストラクターを作成する場合に非常に役立ちます。

class A
{
   private:
      int x;
      int y;
   public:
      A(int a, int b) x(a), y(b) {}
      A(A a) { x = a.x; y = y.x; }
};

または、私たちが書きたい場合operator+、そしてoperator-私たちの大きな数のクラスのために。


これは依存性注入に似ています。プライベート変数にアクセスできない他のクラスのオブジェクトを挿入することもできます。
nageswaran 2013年

確かに、クラスBのオブジェクトからクラスAを構築しようとしていて、Bにプライベートコンポーネントがある場合は、Aをフレンドとして宣言するか、パブリックパーツのみを表示できます[AがBから派生している場合は、保護されている可能性があります]。
Mats Petersson 2013年

javaと.netには、友達の概念はありません。そのような場合、これをどのように処理しますか?
nageswaran 2013年

1

Javaのプライベート可視性のセマンティクスがオブジェクトレベルではなくクラスレベルである理由についての私の2セント。

ここでは利便性がカギだと思います。実際、オブジェクトレベルでのプライベートな可視性により、OPで示されているシナリオでは、メソッドを他のクラス(たとえば、同じパッケージ内)に公開する必要があります。

実のところ、オブジェクトプライベートレベルでの可視性と比較した場合、クラスプライベートレベルでの可視性(Javaによって提供されるような)が問題を引き起こすことを示す例を作成することも見つけることもできませんでした。

とはいえ、可視性ポリシーのよりきめ細かいシステムを備えたプログラミング言語は、オブジェクトレベルとクラスレベルの両方でオブジェクトの可視性を提供できます。

たとえば、Eiffelは、選択的なエクスポートを提供します。{NONE}(object-private)から{ANY}(publicに相当し、デフォルト)、{PERSON}まで、任意のクラス機能を任意のクラスにエクスポートできます。 (class-private、OPの例を参照)、クラスの特定のグループ{PERSON、BANK}。

また、エッフェル塔では、属性をプライベートにして、他のクラスが属性に割り当てないようにするためのゲッターを作成する必要がないことにも注目してください。Eiffelのパブリック属性は、デフォルトで読み取り専用モードでアクセスできるため、値を返すためだけにゲッターは必要ありません。

もちろん、属性を設定するにはセッターが必要ですが、その属性の「割り当て者」として定義することで非表示にできます。これにより、必要に応じて、setter呼び出しの代わりに、より便利な代入演算子を使用できます。


0

のでprivate 、アクセス修飾子は唯一の中、それは目に見えるレンダリングするクラス。このメソッドはまだクラス内にあります。


私の質問は、なぜそれが「クラス内」のように設計されているのに、「オブジェクト内のみ」のように設計されていないのかということです。
nageswaran 2013年

それがJavaの作り方だからです。
darijan 2013年

そして、なぜJavaはJavaがそのように作ったのですか?
nageswaran 2014

Javaは成功しませんでしたが、Javaの作成者は成功しました。どうして?彼らは揺れるからです!
darijan 2014

1
Javaクリエーターは理由なしにそれを行うことはなく、これを行うには何らかの理由が必要です。私は理由を尋ねています
Nageswaran 2014

0

privateフィールドは、フィールドが宣言されているクラス/オブジェクトでアクセス可能です。それは、それが置かれているもの以外の他のクラス/オブジェクトにプライベートです。


-1

ここで最初に理解する必要があるのは、oopsの原則に従う必要があることです。カプセル化とは、パッケージ(つまりクラス)内でデータラップし、すべてのデータをオブジェクトとして表し、アクセスしやすいということです。したがって、フィールドを個別にアクセスするよりも非プライベートにする場合。そしてそれは悪いパラチスになります。


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