在面向物件程式設計中，元類是一種例項是類的類。普通的類定義的是特定物件的行為，元類定義的則是特定的類及其例項的行為。不是所有面向物件程式語言都支援元類。在它能做的事情之中，元類可以覆寫任何給定方面類行為的程度是不同的。元類可以透過使類成為頭等物件來實現，在這種情況下元類簡單的就是構造類的一個物件。每個語言都有它自己的元物件協議，給出物件、類和元類如何互動的規則。 Smalltalk80 元類 在 Smalltalk 中，所有東西都是物件。此外，Smalltalk 是基於類的系統，這意味著所有物件都有一個類，它定義這個物件的結構（比如說這個類擁有例項變數），和這個物件所理解的訊息。二者在一起蘊含了，在 Smalltalk 中，類是一個物件，因此類也需要是它的元類的例項。 元類在 Smalltalk80 系統中的主要角色，是提供協議來初始化類變數，和建立元類的唯一例項（也就是其對應的類）的初始化例項。 例項聯絡 為了允許類擁有它們自己的方法，和叫作類例項變數它們自己的，Smalltalk80 為每個類 C 介入了它們自己的元類 C class。就像例項方法實際上屬於類一樣，類方法實際上屬於元類。在類中定義和，而在元類中定義類例項變數。 每個元類在效果上都是單例類。就像連體雙胞胎，類和元類是共生的。元類有一個例項變數 thisClass，它指向它結合的類。平常的 Smalltalk，不將元類展示為單獨的類，轉而允許一起同時編輯類和它的元類。 要得到一個例項的類，需要向它傳送訊息呼叫 class 方法。類和元類繼承了其超類的 name 方法，它返回接收者名字的字串。例如，轎車物件 c 是類 Car 的例項，則 c class 返回 Car 類物件，而 c class name 返回 Car；依次類推，Car class 返回 Car 的元類物件，而 Car class name 返回依賴於實現，有的是 nil，即沒有名字，有的是 Car class，即用空格分隔的類名字和 class。 在早期的 Smalltalk76 中，建立新類的方式是向 Class 類傳送 new 訊息。在 Smalltalk80 中，Class 是元類的基礎類，它是類而不是元類。所有元類都是一個 Metaclass 類的例項。Metaclass 類是 Metaclass class 的例項，而 Metaclass class 作為元類，也是 Metaclass 類的例項。 繼承聯絡 在 Smalltalk80 中，終端物件是一個整數、一個元件、或一臺車等，而類是像 Integer、或 Widget 或 Car 等這樣的東西，除了 Object 之外，所有的類都有一個超類。元類所繼承的元類，就是元類對應的類所繼承的類的元類。 在一個訊息被髮送到物件的時候，方法的查詢開始於它的類。如果沒有找到則在上行超類鏈，停止於 Object 而不管找到與否。在一個訊息被髮送到一個類的時候，類方法查詢開始於它的元類，並上行超類鏈至 Object class。直至 Object class，元類的超類層級並行於類的超類層級。在 Smalltalk80 中，Object class 是 Class 的子類： Object class superclass Class 類方法的查詢在元類鏈之後仍可繼續下去，所有元類都是 Class 的在繼承層級中的子類，它是所有元類的抽象超類，它描述這些類的一般性質，繼而最終可上溯至 Object。 繼承層級 四個類提供描述新類的設施，下面是它們的繼承層級（起自 Object），和它們提供的主要設施： Object，物件類是所有類的基礎類，它為所有物件提供公共的方法，即公共的預設行為。至少包括了：測試物件的功能比如 class 方法，比較物件，物件複製，訪問物件的各部份，列印和儲存物件，錯誤處理。 Behavior，行為類定義了擁有例項的物件所需要的最小，它提供建立一個類的例項的 new 方法。特別是，它定義了 Smalltalk80 直譯器所用到的狀態，併為編譯方法原始碼提供到編譯器的基本介面，如 compile 等方法。Behavior 描述的這個狀態，包括了一個類層級連線（superclass），一個方法字典（methodDictionary、addSelectorwithMethod），和對例項的描述（依據數目和對它們的變數的表示）。儘管一個類的多數設施都規定在 Behavior 中，但很多訊息不能於此實現，對類的完全描述轉而在它的子類之中提供。 ClassDescription，類描述類為 Class 和 Metactass 提供了共同的超類。它表現類命名（name）、類註釋（comment）、和命名例項變數（addlnstVarName）。特別是，它增加了組織在方法字典中方法（compileclassified）和類自身（category）的結構。它還提供了在外部串流（檔案）上儲存完全的類描述的機制，和記述對類描述的變更的機制。 Class，類類是所有元類的基礎類，從而為所有類提供公共的方法，它定義了初始化類變數的 initialize 方法。Class 的例項描述物件的表現和行為，它提供比 ClassDescription 更具描述性的設施，特別是，它增加了對類變數名字（addClassVarName）和共享的池變數（addSharedPool）的表示。它還提供比 Behavior 更綜合性的程式設計支援設施，比如建立一個類的子類的訊息：subclassinstanceVariableNamesclassVariableNamespoolDictionariescategory。 Metaclass，元類類是建立元類的類，它為所有元類提供公共的方法。Metaclass 的關鍵性的訊息，是自身初始化訊息，這在 GNU Smalltalk 中依舊保留；一個是傳送到 Metaclass 自身的訊息 subclassOf superMeta，用來建立元類 superMeta 的一個子類；一個是傳送到 Metaclass 的一個例項的訊息，用來建立這個元類的唯一例項，對於建立完全初始化的類，它的每個引數都是需要的：nameenvironmentsubclassOfinstanceVariableNamesshapeclassVariableNamespoolDictionariescategory。 方法查詢次序 下面是方法查詢次序的辨析： 每個終端物件，在查詢方法時，都首先查詢自己的類；然後按類繼承鏈上溯，最後不經過 Class（類類）和 Metaclass（元類類），最終上至 Object（物件類）。 每個類，包括 Class 和 Metaclass，在查詢查詢方法時，首先查詢自己的元類；然後按元類繼承鏈上溯，最終經過 Object class（物件元類）而上至 Class；接著按類繼承鏈上溯，不經過與其並列的 Metaclass，最終上至 Object。 每個元類，包括 Class class 和 Metaclass class，在查詢方法時，因為都是 Metaclass 的例項，所以首先查詢 Metaclass；然後按類繼承鏈上溯，不經過與其並列的 Class，最終上至 Object。 示意圖 下面是兩個示意圖，二者都是縱向連線表示例項聯絡，而橫向連線表示繼承聯絡。例項聯絡以 Metaclass（元類類）及其元類為頂端，而繼承聯絡以 Object（物件類）及其元類為中心，其中 Object class（物件元類）繼承 Class（類類）是串接元類繼承鏈與類繼承鏈的關鍵環節。前者圖示採用 Smalltalk80 藍皮書的樣式（但旋轉了 180），將 Metaclass 及其元類放置在最上方的獨立兩行，使得例項聯絡儘量成為樹狀向上匯聚；後者圖示將 Metaclass 及其元類放置在最左邊，使得繼承聯絡儘量都在同一行之上。 FileSmalltalk 80 metaclassessvgSmalltalk80 的類和元類層級，使用 UML 類圖表示，這裡從左至右，第一列是 Class class（類元類）和 Class（類類），第二列是 ClassDescription class（類描述元類）和 ClassDescription（類描述類），第三列是 Behavior class（行為元類）和 Behavior（行為類），第四列是 Object class（物件元類）和 Object（物件類），第五列是 Metaclass class（元類元類）、Metaclass（元類類）、Car class（Car 元類）、Car（Car 類）和 cCar（Car 例項）。 FileSmalltalk metaclasspngSmalltalk 中在類和元類之間的繼承和例項聯絡的示意圖，這裡從左至右，第一列是 Metaclass 元類和 Metaclass（元類類），第二列是 Class 元類和 Class（類類），第三列是 ClassDescription 元類與 Behavior 元類、和 ClassDescription（類描述類）與 Behavior（行為類），第四列是 Object 元類、Object（物件類）和 Object 例項，第五列是 Foo 元類、Foo 類和 Foo 例項，第六列是 Bar 元類、Bar 類和 Bar 例項。 例子 下列例子展示，從 Smalltalk80 派生的 Squeak 和 Pharo 的樣例程式碼的結構，它們的繼承層級的根類實際上是 ProtoObject，ProtoObject 封裝了所有物件都必須擁有的極小化的訊息集合，它被設計為引發儘可能多的錯誤，用來支援代理（proxy）定義。例如 Smalltalk80 的 Object 中，錯誤處理訊息 doesNotUnderstand，和系統原始訊息 become，就轉而在 ProtoObject 中定義了。 在示意圖中，縱向的綠色連線，展示繼承聯絡的 子父 關係（隱含的自下而上），橫向的藍色連線展示例項聯絡的 成員容器 關係，從 x 出的發藍色連線，指向 x 的最小實際容器，它是在呼叫在 x 上的方法時查詢方法的繼承鏈起點： r ProtoObject c Class mc Metaclass Object subclass A A subclass B u B new v B new 這個結構由兩個部份構成，使用者部份有四個顯式的物件和類及其兩個隱式的元類：終端物件 u 和 v，它們連線到的類 A 和 B，它們兩個連線到的右側灰色節點表示的隱式的元類，其他的物件都是內建部份。 ObjectiveC 元類 在 ObjectiveC 中的元類，幾乎同於 Smalltalk80 的元類，這是因為 ObjectiveC 從 Smalltalk 引進了很多東西。就像 Smalltalk，在 ObjectiveC 中例項變數和方法是物件的類定義的。類也是物件，因此它是元類的一個例項。 FileObjectiveC metaclasspng 在 ObjectiveC 中在類和元類之間的繼承和例項聯絡的示意圖。注意 ObjectiveC 有多個根類，每個根類都有獨立的層級。這個示意圖只展示了例子根類 NSObject 的層級。每個其他根類都有類似的層級。 就像 Smalltalk，在 ObjectiveC 中類方法，簡單的是在類物件上呼叫的方法，因此一個類的類方法，必須定義為在它的元類中的例項方法。因為不同的類有不同的類方法集合，每個類都必須有它自己單獨的元類。類和元類總是成對建立：執行時系統擁有函式 objc_allocateClassPair 和 objc_registerClassPair 來分別的建立和註冊類 元類對。 元類沒有名字，但是到任何類物件的指標，可以透過泛化型別 Class 來提及（類似於用作到任何物件的指標的型別 id）。 元類都是相同的類即根類元類的例項，而根類元類是自身的例項。因為類方法是透過繼承聯絡來繼承的，就像 Smalltalk，除了根類元類之外，元類繼承聯絡必須並行於類繼承聯絡（比如說如果類 A 的父類是類 B，則 A 的元類的父類是 B 的元類）。 不同於 Smalltalk，根類元類繼承自根類自身（通常為使用 Cocoa 框架的 NSObject）。這確保了所有的元類最終都是根類的子類，從而人們可以將根類的例項方法，它們通常是針對物件有用的實用方法，使用於類物件自身上。 Python 元類 在 Python 中，內建的類 type 是元類 IBM Metaclass programming in Python parts 1 2 and 3 Artima Forum Metaclasses in Python 30 part 1 of 2 part 2 of 2 。 r object c type class M c pass class A metaclassM pass class B A pass b B 類的定義，不包括它的例項物件的細節，如它們的位元組為單位的大小，它們在記憶體中的二進位制格局，它們是如何分配的，每次建立例項時自動呼叫的__init__方法，諸如此類。不只是在建立新例項物件的時候，而且在每次訪問例項物件的任何特性的時候，這些細節都起到作用。在沒有元類的語言中，這些細節是在語言規定中定義的，並且不能被覆寫（override）。 在 Python 中，元類 type 控制著類行為的這些細節，預設定義出的類自身都是 type 的例項。新的元類可以很容易定義為 type 的子類從而覆寫它，透過向類定義提供 關鍵字引數 metaclass 就可以使用這個新的元類。 type b class __main__B print type B B__bases__ B__dict__ class __main__M class __main__A __module__ __doc__ print type A A__bases__ A__dict__ class __main__M class object __module__ __dict__ __weakref__ __doc__ print type M M__bases__ M__dict__ class type class type __module__ __doc__ print type c c__bases__ class type class object print type r r__bases__ class type sorted r__dict__ c__dict__ __delattr__ __dir__ __doc__ __getattribute__ __init__ __new__ __repr__ __setattr__ __sizeof__ sorted r__dict__ c__dict__ __class__ __eq__ __format__ __ge__ __gt__ __hash__ __init_subclass__ __le__ __lt__ __ne__ __reduce__ __reduce_ex__ __str__ __subclasshook__ sorted c__dict__ r__dict__ __abstractmethods__ __base__ __bases__ __basicsize__ __call__ __dict__ __dictoffset__ __flags__ __instancecheck__ __itemsize__ __module__ __mro__ __name__ __prepare__ __qualname__ __subclasscheck__ __subclasses__ __text_signature__ __weakrefoffset__ mro 例子 考慮下面這個最簡單的 Python 類： class Car def __init__self args kwargs self__dict__update kwargs def __call__self kwargs self__dict__update kwargs property def description self 返回這輛車的描述 return join str value for value in self__dict__values new_car Car makeToyota modelPrius year2005 engineHybrid new_car colorGreen new_cardescription Toyota Prius 2005 Hybrid Green 上面的例子包含了一些程式碼來處理初始化特性，也可以使用元類來完成這種任務： class AttributeInitType type def __new__args kwargs 返回建立的例項類 cls type__new__args kwargs def call self kwargs self__dict__update kwargs cls__call__ call 為例項類增加__call__方法 return cls def __call__cls args kwargs 返回為例項類建立的例項物件 obj type__call__cls args 以正常預設方式建立例項物件。 obj__dict__update kwargs 在這個新物件上設定屬性。 return obj 這個元類只覆寫例項類和物件建立部份功能。元類行為的所有其他方面仍由 type 處理。現在可以重寫類 Car 使用這個新元類： class Car object metaclassAttributeInitType def __init__self args pass 接收未預期的位置實際引數 property def description self 返回這輛車的描述 return join str value for value in self__dict__values Ruby 元類 Ruby 透過介入其自稱的特徵類（eigenclass），提煉了 Smalltalk80 的元類概念，去除了 Metaclass 類，並重新定義了 classof 對映。變更可以圖示如下： classwikitable 類 隱式元類 終端物件 特別要注意在 Smalltalk 的隱含的元類和 Ruby 類的特徵類之間的對應。Ruby 的特徵類模型，使得隱式元類概念完全統一：所有物件 x，都有它自己的元物件，它叫作 x 的特徵類，它比 x 高一個元層級。高階特徵類通常是純粹概念上的存在，在大多數 Ruby 程式中，它們不包含任何方法也不儲存任何（其他）資料。 下面的示意圖展示 Ruby 樣例程式碼的核心結構。這裡的灰色節點表示開啟 A 和 v 特徵類後擴張出來的特徵類。 r BasicObject c Class class A end class B A end u Bnew v Bnew class A end class v end 圖示還展示了 Ruby 中特徵類的惰性求值。v 物件可以有它的特徵類，作為向 v 增加 單例方法 的結果而被求值（被分配）。 在語言和工具中的支援 下面是支援元類的一些最顯著的程式語言。 Common Lisp，透過 CLOS Delphi 和受它影響的其他 Object Pascal 版本 Groovy ObjectiveC Python Perl，透過元類 pragma，還有 Moose Ruby Smalltalk C（規劃用於 C23） 一些不甚廣泛傳播的語言支援元類，包括、OpenC、OpenAda、、ObjVLisp、、MODELK、和 MELDC。其中幾種語言可追溯日期至 1990 年代早期並具有學術價值。 是 Prolog 的面向物件擴充套件，它也支援元類。 資源描述框架（RDF）和統一建模語言（UML）二者都支援元類。 另見 超程式設計 元物件 反射式程式設計 引用 Category 類 計算機科學