コンピューティングにおいて、型イントロスペクションとは、実行時にオブジェクトの型またはプロパティを調べる プログラムの機能です。一部のプログラミング言語にはこの機能があります。
イントロスペクションは、リフレクションと混同しないでください。リフレクションはさらに一歩進んで、プログラムが実行時にオブジェクトのメタデータ、プロパティ、および関数を操作する機能です。一部のプログラミング言語にもその機能があります (例: Java、 Python、 Julia、 Go )。
例
オブジェクティブC
たとえば、Objective-Cでは、汎用 Object と NSObject ( Cocoa / OpenStep内)の両方が、メソッドの引数が指定されたクラスのインスタンスである場合に true を返すメソッド を提供します。同様に、このメソッドは、引数が指定されたクラスから継承されている場合にも true を返します。
isMemberOfClass:isKindOfClass:
たとえば、Appleと、Orangeを継承する クラスがあるとしますFruit。
さて、eatメソッドでは次のように記述できます。
- ( void ) eat: ( id ) sth { if ([ sth isKindOfClass : [ Fruit class ]]) { // 実際に Fruit を食べているので、続行しますif ([ sth isMemberOfClass : [ Apple class ]]) { eatApple ( sth ); } else if ([ sth isMemberOfClass : [ Orange class ]]) { eatOrange ( sth ); } else { error (); } } else { error (); } }
これで、 がeat汎用オブジェクト ( id) で呼び出されると、関数は汎用オブジェクトの型に応じて正しく動作するようになります。
C++
C++ は、実行時型情報(RTTI) typeidおよびdynamic_castキーワードによる型イントロスペクションをサポートしています。dynamic_cast式を使用して、特定のオブジェクトが特定の派生クラスのものであるかどうかを判断できます。例:
Person * p = dynamic_cast < Person *> ( obj ); if ( p != nullptr ) { p -> walk (); }
演算子は、オブジェクトの最も派生した型を記述するオブジェクト
typeidを取得します。std::type_info
typeid ( Person ) == typeid ( * obj ) の場合) { serialize_person ( obj ) ; }
オブジェクトパスカル
型イントロスペクションは、ビジュアル フォーム デザインに RTTI を多用する Delphi の最初のリリース以来、Object Pascal の一部となっています。Object Pascal では、すべてのクラスは基本 TObject クラスから派生しており、このクラスは基本的な RTTI 機能を実装しています。すべてのクラスの名前は、RTTI の目的でコード内で参照できます。クラス名識別子は、クラスのメタデータへのポインタとして実装されており、TClass 型の変数として宣言して使用できます。この言語には、オブジェクトが特定のクラスであるか、または特定のクラスの子孫であるかを判断するis演算子、型チェックされた型キャストを提供するas演算子、およびいくつかの TObject メソッドが含まれています。より深いイントロスペクション (フィールドとメソッドの列挙) は、従来、$M+ (プラグマ) 状態で宣言されたオブジェクト (通常は TPersistent) と、公開セクションで定義されたシンボルに対してのみサポートされていました。Delphi 2010 では、これがほぼすべてのシンボルに拡張されました。
procedure Form1 . MyButtonOnClick ( Sender : TObject ) ; var aButton : TButton ; SenderClass : TClass ; begin SenderClass := Sender . ClassType ; //Senderのクラス ポインターを返します。if sender is TButton then begin aButton : = sender as TButton ; EditBox . Text : = aButton . Caption ; //ボタンが持つプロパティですが、汎用オブジェクトには存在しません。 end else begin EditBox . Text := Sender . ClassName ; //Senderのクラス名を文字列として返します。 end ; end ;
ジャワ
Javaにおける型イントロスペクションの最も単純な例はinstanceof[1]演算子です。このinstanceof演算子は、特定のオブジェクトが特定のクラス(またはそのクラスのサブクラス、またはそのインターフェースを実装するクラス)に属しているかどうかを判定します。例えば、
if ( obj instanceof Person ) { Person p = ( Person ) obj ; p . walk (); }
java.lang.Class[2]クラスはより高度なイントロスペクションの基礎となります。
たとえば、オブジェクトの実際のクラス (特定のクラスのメンバーであるかどうかではなく)を判別することが望ましい場合はObject.getClass()、次のようClass.getName()に使用できます。
システム.out.println ( obj.getClass ( ) . getName ( ) ) ;
PHP の
PHPでは、演算子を使用してイントロスペクションを実行できますinstanceof。例:
if ( $obj instanceof Person ) {
// 好きなようにしてください
}
パール
イントロスペクションは、Perlのrefおよび関数を使用して実現できます。
isa
次のクラスとそれに対応するインスタンスをイントロスペクトできます。
パッケージAnimal ; sub new { my $class = shift ; return bless {}, $class ; }
パッケージDog ;ベース'Animal'を使用します。
パッケージmain ; my $animal = Animal -> new (); my $dog = Dog -> new ();
使用:
print "これは動物です。\n" if ref $animal eq 'Animal' ; print "犬は動物です。\n" if $dog -> isa ( 'Animal' );
メタオブジェクトプロトコル
Perlでは、 Mooseオブジェクトシステム[3]とClass::MOP メタオブジェクトプロトコル[4]を使用することで、より強力なイントロスペクションを実現できます。たとえば、特定のオブジェクトがロールXを実行しているかどうかを確認できます。
if ( $object -> meta -> does_role ( "X" )) { # 何かを実行する ... }
これは、オブジェクトで呼び出すことができるすべてのメソッドの完全修飾名と、それらが定義されているクラスをリストする方法です。
私の$ method ( $object -> meta -> get_all_methods ) { $method -> completely_qualified_nameを印刷し、"\n" ; }
パイソン
Pythonにおける最も一般的なイントロスペクションの方法は、関数を使用してdirオブジェクトの属性を詳細に調べることです。例:
クラス Foo :
def __init__ ( self , val ):
self . x = val
def bar ( self )
: self.xを返す
>>> dir ( Foo ( 5 ))
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']
また、組み込み関数のtypeと はisinstanceオブジェクトが何であるかを判断するのに使用でき、 はhasattrオブジェクトが何をするかを判断するのに使用できます。例:
>>> a = Foo ( 10 )
>>> b = Bar ( 11 )
>>> type ( a )
<type 'Foo'>
>>> isinstance ( a , Foo )
True
>>> isinstance ( a , type ( a ))
True
>>> isinstance ( a , type ( b ))
False
>>> hasattr ( a , 'bar' )
True
ルビー
型イントロスペクションはRubyのコア機能です。Ruby では、Object クラス (すべてのクラスの祖先) はインスタンスのクラスをチェックするためのメソッドObject#instance_of?とObject#kind_of?メソッドを提供します。後者は、メッセージが送信された特定のインスタンスが問題のクラスの子孫のインスタンスである場合に true を返します。たとえば、次のサンプル コードを考えてみましょう ( Interactive Ruby Shellですぐに試すことができます)。
$ irb
irb(main):001:0> A = Class . new
=> A
irb(main):002:0> B = Class . new A => B irb(main):003:0> a = A . new => #<A:0x2e44b78> irb(main):004:0> b = B . new => #<B:0x2e431b0> irb(main):005:0> a . instance_of? A => true irb(main):006:0> b . instance_of? A => false irb(main):007:0> b . kind_of? A => true
上記の例では、Classクラスは Ruby の他のクラスと同じように使用されます。Aと の2 つのクラスが作成されます。前者は後者のスーパークラスであるため、各クラスの 1 つのインスタンスがチェックされます。 は のクラスのスーパークラスであるBため、最後の式は true を返します。
Ab
さらに、任意のオブジェクトのクラスを直接要求し、それらを「比較」することもできます (以下のコードは、上記のコードが実行されていることを前提としています)。
irb(main):008:0> A . instance_of? Class => true irb(main):009:0> a . class => A irb(main):010:0> a . class . class => Class irb(main):011:0> A > B => true irb(main):012:0> B <= A => true
アクションスクリプト
ActionScript (as3)では、この関数をflash.utils.getQualifiedClassName使用して任意のオブジェクトのクラス/型名を取得できます。
// as3で使用されるすべてのクラスは明示的にインポートする必要がありますimport flash.utils.getQualifiedClassName ; import flash.display.Sprite ; // traceは Java の System.out.println または PHP の echo に似ていますtrace ( flash.utils.getQualifiedClassName ( " I 'm a String " ) ) ; // "String" trace ( flash.utils.getQualifiedClassName ( 1 )); // " int"。なぜNumberではないのかについては、動的キャストを参照してくださいtrace ( flash.utils.getQualifiedClassName ( new flash.display.Sprite ( ) ) ) ; // " flash.display.Sprite "
あるいは、演算子isを使用して、オブジェクトが特定のタイプであるかどうかを判断することもできます。
// trace は Java の System.out.println や PHP の echo に似ています。
trace ( "I'm a String" is String ); // true trace ( 1 is String ); // false trace ( "I'm a String" is Number ); // false trace ( 1 is Number ); // true
この 2 番目の関数は、クラス継承の親をテストするためにも 使用できます。
flash.display.DisplayObjectをインポートします。flash.display.Spriteをインポートします。// DisplayObjectを拡張します。
trace ( new flash . display . Sprite () is flash . display . Sprite ); // true trace ( new flash . display . Sprite () is flash . display . DisplayObject ); // true、Sprite は DisplayObject を拡張するためtrace ( new flash . display . Sprite () is String ); // false
メタタイプのイントロスペクション
Perl と同様に、ActionScript はクラス名だけでなく、関数を使用してオブジェクトを構成するすべてのメタデータ、関数、およびその他の要素を取得できます。これは、ActionScript でリフレクションflash.utils.describeTypeを実装するときに使用されます。
flash.utils.describeTypeをインポートします。flash.utils.getDefinitionByNameをインポートします。flash.utils.getQualifiedClassNameをインポートします。flash.display.Spriteをインポートします。
var className : String = getQualifiedClassName ( new flash . display . Sprite ()); // "flash.display.Sprite" var classRef : Class = getDefinitionByName ( className ); // flash.display{{タイプミスではありません|.}}Sprite へのクラス参照// 例: 'new classRef()' は 'new flash.display.Sprite()' と同じtrace ( describeType ( classRef )); // タイプを記述する XML オブジェクトを返す// 次と同じ : trace(describeType(flash.display.Sprite));
参照
参考文献
- ^ Java 言語仕様: instanceof
- ^ Java API: java.lang.Class
- ^ Moose メタ API ドキュメント
- ^ Class::MOP - Perl のメタオブジェクト プロトコル
外部リンク
- Rosetta コードのイントロスペクション
