web-dev-qa-db-ja.com

なぜインスタンスの作成は現状どおりですか?

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

_Person Bob = new Person();
_

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

私が慣習に従っているなら、それはもっと似ているでしょう:

_int XIsAnInt;
Person BobIsAPerson;
_

またはおそらくこれらの1つ:

_Person() Bob;
new Person Bob;
new Person() Bob;
Bob = new Person();
_

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

17

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();

ですから、彼は他のモデレーターとは違った扱いを受けることを許しません。そして、彼はフォーラムをこっそり見て、シークレットモードで全員に連絡を取り続けることを好みます。

StackExchangeMember bob = new StackOverFlowModerator();

それから彼はいくつかの貧弱な最初のポスターを見つけたとき、彼は彼の不可視性のマントを脱ぎ捨てて激突します。

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

その後、彼はすべての無実の行動をとることができます。

((Person) bob).ImNotMeanIWasJustInstantiatedThatWay();
52
radarbob

コードの最初の行を見てみましょう。

_Person Bob = new Person();
_

最初のPerson型指定です。C#では、次のように指定するだけでこれを省略できます。

_var Bob = new Person();
_

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

しかし、あなたはこのようなものを書きたいかもしれません:

_IPerson Bob = new Person();
_

PersonのAPI契約全体ではなく、インターフェースIPersonで指定された契約のみを満たしている場合。

34
Robert Harvey
  1. この構文はC++のレガシーであり、ちなみに次の両方を備えています。

    _Person Bob;
    _

    そして

    _Person *bob = new Bob();
    _

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

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

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

    ここでは2つの異なることを行っています。ローカル変数numsのタイプを示し、タイプ 'List'の新しいオブジェクトを作成してそこに配置するとします。

  3. C# ほとんどの場合、変数の型はユーザーが入力したものと同じであるため、ある程度同意します。

    _var nums = new List<int>();
    _
  4. 一部の言語では、変数の型を F# のように宣言しないように最善を尽くします。

    _let list123 = [ 1; 2; 3 ]
    _
21
AK_

_int x_と_Person bob_の間には大きな違いがあります。 intintintであり、常にintである必要があり、int以外にすることはできません。 intを宣言するときに初期化しない場合でも(_int x;_)、デフォルト値に設定されたintのままです。

ただし、_Person bob_を宣言する場合、bobという名前がいつ実際に何を参照するかについては、かなりの柔軟性があります。 Personを参照することも、他のクラスを参照することもできます。 ProgrammerPersonから派生;オブジェクトをまったく参照しない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つを違法にする)。彼らは、非常に簡潔なコードを書くよりも、言語を「単純」に保つことにもっと関心を持っていました。これは、より短い代替構文を提供しないという彼らの決定に影響を与えた可能性がありますが、いずれにしても、それは必要ではなく、提供しませんでした。

3
David K

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

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

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

2つのタイプが異なるもう1つの例は、インスタンス化する特定のサブクラスを選択し、それを基本タイプとして返​​すファクトリメソッドにあります。これにより、呼び出し側は実装の詳細、たとえば「ポリシー」の選択を意識する必要がなくなります。

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

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

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

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

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

auto p = new Person();
1
Jerry101

素人の言葉で:

  • 宣言をインスタンス化から分離することで、オブジェクトを使用する人と作成者を切り離すことができます。
  • これを行うと、インスタンス化された型が宣言型のサブタイプである限り、変数を使用するすべてのコードが機能するため、多態性が有効になります。
  • 強く型付けされた言語では、その型を示す変数を宣言する必要があります。単にvar = new Process()を実行するだけで、最初に変数を宣言するわけではありません。
1

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

Person somePerson;

自動的にと同じでした

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

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

この例は Joshua BlochEffective Javaで説明されています(皮肉にもアイテム1です!)

0