0

.NET と Java のオブジェクト指向プログラミングについてよく理解しています。Java と .NET のすべてがオブジェクトから派生していることを理解しています。

私の質問は、プリミティブ型に関するものです。プリミティブ型は Object から派生しないことを理解しています。また、それらがどのくらい広いか (バイトは 8 ビット、整数は 32 ビット) も理解しています。また、ボクシングがオブジェクトに相当することも理解しています。

私の質問は、プリミティブ型がオブジェクトでない場合、実際にどのように実装されているのですか? 私はコンパイラ理論について少し知識がありますが、おそらくもっと掘り下げる必要があります。

私のSCJPの本には、「プリミティブ型を除外すると、Javaのすべてがオブジェクトになります」と書かれています。私の .NET 本にも同じことが書かれています。詳細には触れません。

私はJavaのバックグラウンドから来ており、Javaはオブジェクト指向(.netなど)であるため、この質問でJavaについて話しました。ただし、.NET 固有の回答を探しています。

4

5 に答える 5

3

Java では、プリミティブ型は type から派生しませんjava.lang.Object。結果として、java.lang.Integerプリミティブint型をラップする追加のクラス (プリミティブ型など) が存在するため、参照変数に格納できます。

CLR もプリミティブ型を認識していますが、それらは構造体として定義されています。すべての構造体は内部的に から派生しSystem.ValueType、さらに から継承しSystem.Objectます。C#の名前int、などは、.NET フレームワークの 、 などの構造体型の単なるエイリアスです。これらの型は CLR で特別に処理されますが、Java とは異なり、統一された型階層の一部です。doubleSystem.Int32System.Double

この点で、Java VM と CLR は大きく異なります。Java では、型intと型java.lang.Integerは完全に独立していますが、コンパイラーがそれらの間の変換方法を知っているという事実を除きます。CLR にはSystem.Int32、ボックス化された形式とボックス化されていない形式のいずれかで表示できる型が 1 つだけあります。

于 2012-07-29T10:58:09.010 に答える
2

掛けるメガネにもよります。「実装」メガネを使用している場合は、参照型の値にオブジェクト ヘッダーがあることがわかります。System.Object を継承します。オブジェクト ヘッダーには、ハッシュ コードなどのさまざまな情報を格納する同期ブロックと、Monitor.Enter() を呼び出したスレッド ID の 2 つのフィールドがあります。重要なフィールドは 2 番目のメソッド テーブル ポインターです。オブジェクトの種類を識別します。メソッド テーブルには、クラスのメソッドのアドレスが含まれています。これは常に、Object が実装するメソッドである Equals、GetHashCode、および ToString から始まります。

同じ眼鏡をかけていると、値型の値にはこのオブジェクト ヘッダーがありません。値を格納するために必要なスペースのみを占有します。bool には 1 バイト、Char には 2 バイト、int には 4 バイトなど。これにより、値型が非常に効率的になります。

2番目にかけられるメガネは「型式」メガネです。値型の値は、常にオブジェクトに変換できます。帰ってきた。この変換は、ボックス化変換と呼ばれます。戻ることをボックス化解除と呼びます。実装メガネをすばやくポップすると、これら 2 つのフィールドを持つオブジェクトが実際に取得されていることがわかります。メソッド テーブル ポインターは値の型を識別します。メソッド テーブルには、追加のメソッド ポインターがあります。IConvertible の場合と同様に、値型によって実装されるインターフェイスです。これらの 2 つのフィールドを超えるオブジェクトの残りの部分は、値型の値のビットで占められています。ボクシング変換前の単純な値だったときと同じビット。ボックス化されたオブジェクトは、すべての参照型オブジェクトと同様に、ガベージ コレクション ヒープに存在します。

ほとんどの場合、C# または VB.NET コンパイラはボックス化変換を完全に自動的に適用します。コードにキャストを自分で記述する必要はありません。たとえば、ToString または IConvertible メソッドの 1 つを呼び出すと、無料でボクシング変換を取得できます。

これにより、値型が System.Object から継承されているという錯覚が生じます。「型システム」メガネを着用している人は誰でも、値型が Object から完全に継承されていると主張するでしょう。「実装」メガネを着用している場合、ボクシングについて少し心配する傾向があります. 大幅に最適化されていますが、無料ではありません。変換を行うには CPU サイクルがかかり、ボックス化された値型の値はより多くのスペースを必要とし、ガベージを作成します。ジェネリック コレクション型が古い System.Collection クラスを完全に置き換えた理由の 1 つです。

于 2012-07-29T14:46:10.173 に答える
1

簡単な答え: プリミティブ型は System.Object から派生し、.net の他の型と同様に実装されます。

長い答え: ただし、プリミティブ型は、それらをサポートするクラスが組み込み型としてコンパイラによって認識されるため、.NET ではそう呼ばれます。また、プリミティブ型は参照型ではなく、値型 ( .net では軽量型とも呼ばれます) であるため、マネージド ヒープではなくスレッド スタックに割り当てられます。

例えば:

var a = new Int32(16);
var b = 16;

どちらの宣言も同じ IL 命令を生成します。コンパイラはb = 16b = new Int32(16)として解釈します。コンパイラは、組み込みの軽量型/プリミティブを含むコードに対して、次のような最適化を行います。

int a = 1 + 2;

次のようにコンパイルされます。

int a = 3;

確かに、それほど明白ではない最適化が他にもありますが、それについては十分に説明する必要があります。

ポイントは型と軽量型(プリミティブが属する)の違いです。2 つのタイプの違いについて説明している記事を次に示します。これは良い出発点です: http://msdn.microsoft.com/en-us/magazine/cc301569.aspx

于 2012-07-29T10:59:22.223 に答える
1

それはかなり間違っています。.NET では、「プリミティブ」型 (= 値型)実際には から派生しSystem.Objectます。ただし、それらは型システムに関する限りのみそうします。それらの扱いは、依然として参照型とは異なります。

これは、コンパイラとランタイムでの特別な処理によって簡単に処理されます。これの最も簡単な実装は、参照型がヒープ割り当てストレージへのポインターを介して実装されるのに対し、値型は単純に実装されないことです。ただし、これは厳密には Microsoft の CLR (.NET) の実装の実装の詳細であることに注意してください。他の実装では、これを別の方法で処理する場合があります。

于 2012-07-29T10:06:12.587 に答える
0

プリミティブ型は Object から派生していないことを理解しています

オブジェクトから継承します。System.Int32たとえば、(VB.NETが変換するものです)を参照してくださいInteger

Java と同様に、.NET では、Objectプリミティブ型を含むすべての型が から継承されます。

言語プリミティブ型として表示されるものは、コンパイル中に から継承される対応する CLR 型に変換されObjectます。

于 2012-07-29T10:05:25.940 に答える