インスタンス作成がそのままなのはなぜですか?


17

私は過去6か月ほどの間にC#を学び、現在はJavaを掘り下げています。私の質問は、インスタンスの作成に関するものです(どちらの言語でも)、それはもっと多くのことです。この例を取ります

Person Bob = new Person();

オブジェクトが2回指定されている理由はありますか?ありsomething_else Bob = new Person()ますか?

私が慣習に従っているなら、もっと似ているように思えます:

int XIsAnInt;
Person BobIsAPerson;

または、おそらく次のいずれかです。

Person() Bob;
new Person Bob;
new Person() Bob;
Bob = new Person();

「それがまさに行われている方法」よりも良い答えがあるかどうか興味があります。


26
Personがサブタイプの場合はどうなりLivingThingますか?あなたは書くことができますLivingThing lt = new Person()継承とインターフェイスを探します。
xlecoustillier

2
Person Bob宣言する変数「を参照タイプのをPerson呼ばれます」Bob。オブジェクトをnew Person()作成しPersonます。参照、変数、オブジェクトは3つの異なるものです!
user253751

5
冗長性に悩まされていますか?それでは、なぜ書いてみませんvar bob = new Person();か?
200_success

4
Person Bob();C ++で可能であり、Person Bob = Person();
ユーザー60561

3
@ user60561いいえ、引数を取らずにPersonを返す関数を宣言します。
ニコライ

回答:


52

something_else Bob = new Person()はありますか?

はい、継承のためです。次の場合:

public class StackExchangeMember : Person {}

次に:

Person bob = new StackExchangeMember();
Person sam = new Person();

ボブも人間です。そして、彼は他の誰とも違う扱いを受けたくありません。

さらに、ボブに超大国を授けることができます。

public interface IModerator { }
public class StackOverFlowModerator : StackExchangeMember, IModerator {}

IModerator bob = new StackOverFlowModerator();

ですから、彼は他のモデレーターとは違った扱いを受けることをstandしみません。そして、彼はフォーラムの周りをこっそり見て、シークレット中にすべての人が並んでいることを好みます:

StackExchangeMember bob = new StackOverFlowModerator();

それから彼はいくつかの貧しい最初のポスターを見つけたとき、彼は不可視性のマントを投げ捨てて襲いかかります。

((StackOverFlowModerator) bob).Smite(sam);

そしてその後、彼はすべての罪のないものを行動することができます:

((Person) bob).ImNotMeanIWasJustInstantiatedThatWay();

20
オブジェクト名を小文字にした場合、これはより明確になります。
モニカとの軽さのレース

38
仕様の良い例; 継承の悪い例。これを読んでいる他の人には、継承を使用してユーザーの役割を解決しようとしないでください。
アーロンノート

8
@Aaronaughtは正しいです。異なるタイプの人々のために別々のクラスを作成しないでください。ビットフィールドを使用しenumます。
コールジョンソン

1
@Aaronaughtやってはいけないことを言っているのはとても上手ですが、代わりに人々がすべきことを言わずにあまり役に立たないのです。
ファラプ

5
@Pharap:他のいくつか 質問で、私はまさにそれをしました。簡単な答えは、ユーザー(認証/ ID)とセキュリティポリシー(承認/許可)は別々の懸念事項として扱われるべきであり、セキュリティポリシーの標準モデルはロールベースまたはクレームベースであるということです。継承は、LDAP実装やSQL実装など、実際に認証を行うオブジェクトを記述するのに役立ちます。
アーロンノート

34

コードの最初の行を取り上げて調べてみましょう。

Person Bob = new Person();

1つPerson型の仕様です。 C#では、単に言うことでこれを省くことができます。

var Bob = new Person();

コンパイラーは、コンストラクター呼び出しから変数Bobの型を推測しますPerson()

しかし、次のようなものを書きたいかもしれません。

IPerson Bob = new Person();

PersonのAPIコントラクト全体ではなく、interfaceで指定されたコントラクトのみを満たす場合IPerson


2
+1:IPersonコード内の例を実行して、別のIPerson実装にコピー/貼り付け可能なコードを記述するときに、誤ってプライベートメソッドを使用しないようにします。
コートアンモン-復活モニカ

D:私はあなたがそこにタイプミスがあると思う@CortAmmon、明らかにあなたは、そのコードのpastable「多型との仕事」ではなくコピー/意味
ベンジャミンGruenbaum

@BenjaminGruenbaum確かに、多型の定義について;-)
Cort Ammon-Reinstate Monica

@CortAmmon誤ってプライベートメソッドを呼び出す方法は?確かにあなたは意味internal
コールジョンソン

いずれにしても@ColeJohnson。どこで実行する特定のケースを考えることprivateは意味があると書きました:インスタンス化されるクラスの一部であるファクトリーメソッド。私の状況では、プライベート値へのアクセスは例外であり、標準ではありません。私はコードに取り組んでいます。このようにすると、自分でプライベートメソッドを使用する可能性が低くなるだけでなく、次の開発者がこの数十個の場所をコピー/ペーストし、その後開発者がそれらをコピーすると、誰かが「通常の」動作としてプライベートメソッドを使用します。
コートアンモン-モニカーの復活

21
  1. この構文は、C ++からのレガシーです。ちなみに、次の両方があります。

    Person Bob;

    そして

    Person *bob = new Bob();

    最初は現在のスコープ内でオブジェクトを作成し、2番目は動的オブジェクトへのポインターを作成します。

  2. あなたは間違いなく持つことができます something_else Bob = new Person()

    IEnumerable<int> nums = new List<int>(){1,2,3,4}

    ここでは、ローカル変数の型を指定して、nums「リスト」型の新しいオブジェクトを作成してそこに配置するという2つの異なることを実行しています。

  3. ほとんどの場合、変数の型はあなたがそれに入れたものと同一であるため、C#の種類はあなたに同意します:

    var nums = new List<int>();
  4. 一部の言語では、F#のように変数のタイプを指定しないように最善を尽くしています。

    let list123 = [ 1; 2; 3 ]

5
2番目の例では、新しいBobオブジェクトへのポインターを作成すると言う方がおそらくより正確です。物事を保存する方法は、技術的には実装の詳細です。
ロバートハーヴェイ

4
「最初にスタック上にローカルオブジェクトを作成し、2番目にヒープ上にオブジェクトを作成します。」ああ、この誤報ではない。
モニカとの軽さのレース

@LightnessRacesinOrbitの方が良いですか?
AK_

1
@AK_「動的」はほとんど「ヒープ」を意味しますが(ヒープがプラットフォームで使用されるメモリモデルの場合)、「自動」は「スタック」とはまったく異なります。を実行するとnew std::pair<int, char>()、メンバーfirstsecondペアのメンバーは自動ストレージ期間を持ちますが、おそらくヒープに(dynamic-storage-duration pairオブジェクトのメンバーとして)割り当てられます。
モニカの

1
@AK_:はい、これらの名前は正確にそれらが意味することを暗示していますが、この「スタック」対「ヒープ」ナンセンスはそうではありませ。それが全体のポイントです。あなたがそれらを混乱させると私たちがそれらを教える必要性を強化するだけであるので、あなたがそれが馴染みがあるという理由だけであなたが不正確/不正確な用語に頼らないように!
モニカとの軽さのレース

3

との間には大きな違いがint xありPerson bobます。Anがintされintているint、それは常にでなければならないintと以外のものになることはありませんintint宣言するときにを初期化しない場合(int x;)でもint、デフォルト値に設定されたままです。

Person bobただし、を宣言すると、その名前bobがいつでも実際に参照する可能性があるという点で、かなりの柔軟性があります。これは、を参照することができるPerson、またはそれはいくつかの他のクラス、例えばを参照することができるProgrammerから派生し、Person。それも可能性がnull全くのオブジェクトを参照します、。

例えば:

  Person bob   = null;
  Person carol = new Person();
  Person ted   = new Programmer();
  Person alice = personFactory.functionThatReturnsSomeKindOfPersonOrNull();

言語設計者は、確かにPerson carol = new Person()、より少ないシンボルと同じことを達成する代替構文を作成できましたが、それでも許可する必要がありましたPerson carol = new Person() (または、上記の4つの例の特定の1つを違法にする何らかの奇妙なルールを作成しなければなりませんでした)。彼らは、非常に簡潔なコードを書くよりも、言語を「シンプル」に保つことに関心がありました。それは、より短い代替構文を提供しないという彼らの決定に影響したかもしれませんが、いずれにしても、それは必要ではなく、彼らはそれを提供しませんでした。


1

2つの宣言は異なる場合がありますが、多くの場合同じです。Javaの一般的な推奨パターンは次のようになります。

List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

これらの変数listmapは、インターフェイスListを使用して宣言されMap、コードは特定の実装をインスタンス化します。このように、コードの残りの部分はインターフェイスのみに依存し、インスタンス化するために別の実装クラスを選択するのは簡単TreeMapです(コードの残りの部分はインターフェイスHashMapの外部にあるAPI のどの部分にも依存できないため)Map

2つのタイプが異なる別の例は、インスタンス化する特定のサブクラスを選択し、ベースタイプとして返​​すファクトリメソッドで、呼び出し側が実装の詳細(「ポリシー」の選択など)を意識する必要がない場合です。

型推論により、ソースコードの冗長性を修正できます。例えば、Javaで

List<String> listOne = Collections.emptyList();

型推論と宣言のおかげで適切な種類のリストを構築します

static <T> List<T> emptyList(); 

一部の言語では、型推論はさらに進んでいます(C ++など)

auto p = new Person();

ところで、Java言語では、などの小文字の識別子名を使用するための強力な規則が設定されてbobBobます。これにより、package.ClassとClass.variableなど、多くのあいまいさが回避されます。
Jerry101

...そしてそれがあなたが持っている理由ですclazz
CVn

いいえ、clazzので、使用されているclassキーワードである、それは、識別子として使用することはできませんので。
Jerry101

...命名規則がそのままでは問題になりません。 Classは完全に有効な識別子です。
cHao

...現状のままcLaSscLASSおよびcLASs
el.pescado

1

素人の言葉で:

  • インスタンス化から宣言を分離すると、オブジェクトを使用するユーザーとオブジェクトを作成するユーザーを分離できます。
  • インスタンス化された型が宣言型のサブタイプである限り、変数を使用するすべてのコードが機能するため、ポリポーフィズムが有効になります
  • 強く型付けされた言語では、型を示す変数を宣言する必要がありますvar = new Process()。最初に変数を宣言しないようにするだけです。

0

また、何が起こっているかを管理するレベルについても重要です。オブジェクト/変数の宣言がコンストラクタを自動的に呼び出す場合、たとえば

Person somePerson;

自動的に同じでした

Person somePerson = new Person(blah, blah..);

デフォルトコンストラクターではなく(たとえば)静的ファクトリーメソッドを使用してオブジェクトをインスタンス化することはできません。つまり、新しいオブジェクトインスタンスのコンストラクターを呼び出したくない場合があります。

この例は、Joshua BlochEffective Java(項目1は皮肉にも十分です!)で説明されています


本に関しては、私のC#本とJava本の両方がJoyce Farrellからでした。それはコースが指定したものです。また、C#とJavaのさまざまなyoutubeビデオで両方を補完しています。
ジェイソンウォルゲムート

私は、これがどこから来たのかについて言及するだけで、批判していませんでした
デビッドショールフィールド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.