runtime官方文檔

OC是一種面向對象的動態語言,作為初學者可能大多數人對面向對象這個概念理解的比較深,而對OC是動態語言這一特性了解的比較少。那么什么是動態語言?動態語言就是在運行時來執行靜態語言的編譯鏈接的工作。這就要求除了編譯器之外還要有一種運行時系統來執行編譯等功能。OC中這個系統就是runtime。

OC的runtime是用C語言和編譯語言編寫的一個runtime庫,它使C語言有了面向對象的特性。

版本

OC中的運行時分為兩個版本——Modern Runtime和Legacy Runtime。現在的運行時與遺留的運行時區別在雨:遺留的運行時在改變一個類的結構時,你必須繼承它并重新編譯。而現在的運行時可以直接編譯。

iPhone應用程序和64程序在OX v10.5和以后使用現在版本的運行時。其他項目的使用的都是遺留版運行時。

OC程序與運行時系統交互分為三個不同等級:通過OC源代碼;通過定義在Foudation框架中NSObject中的方法;通過直接調用運行時的函數。

通過OC源代碼

在大多數情況下,運行時會自動在幕后工作。你使用它只是編寫和編譯OC源代碼。

當你編譯的代碼包含OC中的類和方法時,編譯器創建數據結構和函數調用,實現語言的動態特性。數據結構捕獲類,分類和協議中聲明的信息。其中包括在OC中討論類和協議對象的定義,以及從源代碼中提取出來方法選擇器,實例模板和其他信息。運行時的主要功能就是傳遞消息,正如消息傳遞中所描述的那樣。它通過源代碼消息表達式來來調用。

通過NSObject中定義的方法

在Cocoa中,大多數對象是NSObject類的子類對象,所以大多數對象繼承了他定義的方法(NSProxy類除外)。因此它的方法建立每個實例,每個類對象的行為。然而在少數情況下,NSOject只定義了一個怎樣去做的模板,它本身不提供所有必要的代碼(抽象類?)

例如,NSObject定義了一個返回一個描述類內容的字符串的實例方法。這主要用于調試GDB對象打印命令從這各類中打印的字符串。NSObject的方法實現中不知道類中包含什么內容,所以它返回一個包含對象名和地址的字符串。NSObject的子類可以實現這個方法返回更多的細節。例如,Foundation中NSSArray返回一個它包含對象的描述列表。

NSObject方法的一些簡單的查詢的運行時系統信息。這些方法允許對象自省(自我查找)。這種方法的例子是類方法,例如isKindOfClass:問一個對象來確定它的類:isMemberOfClass測試對象在繼承結構中的層次位置,respondsToSelector,這表明一個對象是否能接受特定的消息,conformsToProtocol:確定對象是否實現在特定協議中定義的方法,methodForSelector:提供方法實現的地址。像這樣的方法給予了對象自省的能力。

直接調用運行時的函數

運行時系統是一個定義在/usr/include/objc目錄下的,有一個公共接口在它頭文件中包含一系列方法和數據結構動態共享庫。這里面許多方法允許你使用C語言重復編譯器在你寫OC代碼時是怎樣工作的。其他基礎功能形式通過NSObject類的方法來導出。當OC中不需要時,這些方法使開發runtime的其他接口,生產出增強開發環境的工具成為可能。然而,一小些運行時函數只能在編寫OC程序時有用。所有的功能都記錄在Objective-C Runtime Reference.中。

消息傳遞機制

這一部分描述了如何把消息表達式轉換成objc_msgSend函數調用,怎樣通過名字找到方法。然后解釋了如果你需要的話怎么通過objc_msgSend來繞過動態綁定。

在OC中,消息不跟方法實現綁定直到運行時。編譯器將消息表達式 [receiver message] 轉化成一個消息傳遞函數objc_msgSend。這個函數將接收者和在消息中提到的方法名(方法選擇器)作為他的兩個主要參數:objc_msgSend(receiver, selector)。消息中任何參數也交給objc_msgSend:objc_msgSend(receiver, selector, arg1, arg2, ...)。

消息傳遞函數為動態綁定做了所有必須的事情:

它首先發現方法選擇器指向的程序(方法的實現)。因為相同的方法可以被不同的類分別實現。這個準確的程序依賴于接收者的類。

然后調用程序,通過接收對象(指針指向他的數據)為方法傳遞指定的參數。

最后,當他返回值的時候它傳遞程序的返回值。

提示:編譯器對消息傳遞函數生成調用,在你的代碼中不要直接調用。

消息傳遞機制的關鍵在于編譯器對每個類和對象的結構的構建,每個類結構包含兩個基本元素:指向父類的指針和類調度表。這個表羅列了他們定義的有明確類特征的方法的地址的方法選擇器。例如,setOrigin::方法的選擇器與setOrigin::方法的實現聯系起來,展示方法的選擇器關聯展示的地址等等。

創建新對象時,分配內存,實例變量被初始化。首先在對象中有一個指向它的類結構的指針變量。這個指針被稱為isa指針,它使對象能夠訪問類,通過類可以訪問它繼承的所有的類。

注意:雖然不是嚴格意義上語言的一部分,isa指針需要一個對象運行在OC運行時系統。一個對象需要等效的objc_object結構體無論是定義在這個結構的任意字段。然而,你很少甚至從來不需要創建你自己的根對象,繼承自NSObject 或者 NSProxy的對象自動擁有可變的isa指針。

這些類的元素和結構如下圖:


類的元素和結構

當一個消息傳遞給一個對象的時候,消息函數沿著這個對象的isa指針在調度表找到它建立起方法選擇器的類結構。如果它不能在這里發現選擇器,obic_msgSend根據指針找到它的父類,在父類的調度表中尋找選擇器。連續失敗導致objc_msgSend沿著類繼承結構直到尋找到NSObject類。一旦確定選擇器的位置,函數調用表中的方法并且把它傳給接收對象的數據結構。

這就是運行時方法選擇實現的選擇方法,在面向對象的編程術語中我們可以說方法和消息是動態綁定的。

為了加速消息傳遞過程,在方法被使用時,運行時系統緩存了方法的選擇器和地址。每個類都有一個單獨的緩存,它包含了繼承的方法和自己類中定義的方法的選擇器。在查找調度表之前,消息例行程序首先會在接收者對象的類的緩存中查找。(理論上來說,用過一次的方法很可能再次被使用)如果方法選擇器在緩存里面,消息傳遞只會比函數調用慢一點。如果一個程序運行的足夠長的事件來“熱身”緩存,幾乎所有的他發送的消息可以找到一個緩存的方法。當程序運行時,緩存根據新發送的消息動態增長。

使用隱藏參數

當objc_msgSend找到一個方法的實現程序,它調用這個程序,傳遞消息中的所有參數。它也傳遞給程序兩個隱藏參數:接收對象和方法選擇器

這些參數給了每個方法實現關于調用它的兩部分消息表達的明確信息,它們被說成隱藏的是因為它們在定義方法的源代碼中沒有聲明。當代碼被編譯的時候它們被插入實現中。

雖然這些參數沒有被顯式聲明,源代碼仍然可以引用他們(就像它可以接收實例變量一樣)一個方法引用接收對象作為自己,引用他自己的方法選擇器作為_cmd。在下面的實例中,_cmd引用strange方法的選擇器,自己作為strange消息的接收對象。


Self比兩個參數更有用。事實上,這是接收對象的實例變量提供了方法的定義方式。

獲取方法地址

為了避免動態綁定的唯一方法是得到一個方法的地址,當他是函數的時候直接調用。這可能是極少數的情況下是合適的,當一個特定的方法陸續執行了很多次,你想節省每次方法調用時的開銷。

一個定義在NSObject中的方法,methodForSelector:,你可以要求一個指針指向它,然后通過指針來調用他。methodForSelector:這個指針必須返回正確的函數類型。同時返回值和參數的類型也應該包含在內。

下面的例子展示實現setFilled:方法的程序可能是如何被調用的:


setFilled


首先兩個參數傳遞給接收對象是self方法選擇器是_cmd的程序。這些參數被隱藏在方法的語法中但是在這個方法作為一個函數調用的時候必須明確。

使用methodForSelector:規避動態綁定可以節省大多數信息傳遞的時間。然而,只有當一個特定的方法執行很多次的時候節省的消耗才比較明顯,就像上面for循環所示。

注意:methodForSelector:是運行時系統提供的而不是OC的特點。

動態方法解析

這一章講述了你可以動態的提供一個方法的實現

有某種情況下,你可能需要動態地為你的方法提供實現。比如,這個OC聲明屬性中包含@dynamic指令的時候:

@dynamic propertyName;

它告訴編譯器與屬性相關聯的方法將動態提供。

你可以實現方法resolveinstancemethod:和resolveclassmethod:分別為實例和類方法提供一個選擇器。

OC方法是一個至少包含self和_cmd兩個參數的C函數。當一個方法使用class_addMethod函數的時候可以為一個類添加函數。因此,給了以下函數:

void dynamicMethodIMP(id self, SEL _cmd) {// implementation ....}

你也可以把它作為一個方法添加到一個類中(調用resolveThisMethodDynamically)就像這樣:

@implementation MyClass+ (BOOL)resolveInstanceMethod:(SEL)aSEL
{if (aSEL == @selector(resolveThisMethodDynamically)) { class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:"); return YES; } return [super resolveInstanceMethod:aSEL]; } @end

方法轉發和動態方法解析在很大程度上是有關系的。一個類可以在消息轉發機制起作用前動態提供一個方法。如果respondstoselector:或instancesrespondtoselector:被調用時,動態方法解析器首先有機會為選擇器提供IMP。如果你只不過是實現了resolveInstanceMethod:想要通過轉發機制轉發特別的選擇器,你應該為那些選擇器返回NO;

動態加載

一個OC在它運行的時候可以加載鏈接很多類和分類。加入的新代碼和一開始加載的類和分類做相同處理。

動態加載可以用來做很多不同的事情。比如在系統偏好設置的各個模塊中動態加載。

在Cocoa中,動態加載經常被用于程序定制。別人修改寫你在運行時加載的程序,比如說當界面生成器加載自定義調色板和OS X系統偏好設置自定義模塊加載應用程序的偏好的時候。加載模塊擴展你的應用程序。他們有助于你允許但沒有預計或者定義。你可以提供框架別人提供代碼。

即使runtime函數提供了在Objective-C Mach-O文件動態加載模塊,然而Cocoa的NSBundle類提供了一個面向對象的動態加載和相關服務集成更方便的接口。可以在Foudation框架引用中查找NSBulde的詳細說明和它如何讓使用。

消息轉發

如果你給一個不處理這個消息對象發送消息,在認識到時一個錯誤之前運行時會給對象發送一個帶有NSInvocation對象作為唯一參數的forwardInvocation:消息。這個NSInvocation封裝了原始的消息,參數通過它傳遞。

你可以通過實現forwardInvocation:方法來指定一個默認的響應或者通過其他方式來避免這個錯誤。正如它的名字按時的那樣,forwardInvocation:通常用于抓發消息給另一個對象。

要查看轉發的范圍和意圖,你可以想象以下情況:首先,你假設你正在設計一個可以響應談判消息的對象,并且他可以響應另外一種對象的響應。你可以輕易地通過發消息給另外一個包含你實現談判方法的對象來實現。

進一步說,你想你的對象對于談判消息的精確的在另外一個類中響應。實現這一方法的方式是讓你的類繼承于別的類的方法。然而,它不可能通過這種方式來安排事情。這有很多好的為什么你的類和實現了談判的類在繼承結構的不同分支的原因。

即使你的類不能繼承談判方法,你也可以通過實現一個簡單傳遞給另一個類的實例消息的方法中的一個版本來“借用”它:

- (id)negotiate
{if ( [someOtherObject respondsTo:@selector(negotiate)] )return [someOtherObject negotiate];return self; }

這種方式可能有點麻煩,特別是當你希望你的對象傳遞一些消息給另外一個對象的時候。你不得不實現每個你想從其他類中借用的方法。然而,在你寫代碼的時候你不可能處理你不知道所有你想要轉發的消息的集合的情況。這個集合可能依賴于運行時中的事件,也可能在將來新實現類和新方法的時候改變。
forwardInvocation:消息提供了第二個機會:另外一個不是那么特別的解決方案,是動態而不是靜態。它是像這樣工作的:當一個對象因為沒有這個消息對應的方法選擇器來響應這個消息。運行時系統通過發forwardInvocation:消息通知對象。每個對象都從NSObject類中繼承了一個forwardInvocation:方法。然而,NSObjcet類中的方法版本只是僅僅調用了doesNotRecognizeSelector:。通過重寫NSObject類實現的你自己的版本,forwardInvocation:消息提供想另一個對象轉發消息的時候抓住這個機會。
forwardInvocation:轉發消息時所有該做的事情是:1.確定消息要傳到哪2.帶著原始參數把它發送過去。
消息會隨著invokeWithTarget:方法發送:

- (void)forwardInvocation:(NSInvocation *)anInvocation
{if ([someOtherObject respondsToSelector:[anInvocation selector]])[anInvocation invokeWithTarget:someOtherObject];else[super forwardInvocation:anInvocation]; }

轉發消息的返回值返回給原始發送者。所有類型的返回值都可以傳遞給發送者,包括id類型,結構體,單精度和雙精度浮點數。
forwardInvocation:像一個為無法識別消息工作的分配中心,把他們打包到不同的接收器。也可以作為一個中轉站,把所有信息發送到一個目的地。他可以轉運一些消息到其他地方,也可以“吞食”一些方法,所以這里沒有響應和錯誤。forwardInvocation:也可以把幾條消息合并到一個響應中。forwardInvocation:做的是把上交給實現者。然而,它為在轉發鏈上上的連接對象打開了程序設計的可能。
注意:forwardInvocation:方法只能處理那些名義上沒有存在調用方法的消息。例如,你想要你的對象轉發談判消息給另外一個對象,它不能有自己的談判方法。如果有,消息永遠不會到達nominal receiver。

轉發和多繼承

轉發模擬繼承,可為OC程序提供多繼承效果,如下圖所示,一個對象響應一個消息可以通過借用或者繼承其他類的方法實現


在本示例中,戰士類的一個實例將談判消息轉發到外交官類的一個實例。談判的戰士將會出現像一個外交官。似乎將應對談判信息,,實際上它回應(盡管它真的是一個外交官做的工作)

轉發消息的對象因此“繼承”來自兩個繼承層次結構的方法,一個是自己的分支,另一個是響應這個消息的對象。在上面的示例中,這看起來就像是戰士類繼承自外交官以及自己的超類。
轉發提供了大多數你想從多繼承活的功能。然而,兩者之間最大的區別在于:多繼承是結合不同的功能在一個對象中。它傾向于大的,多方面的對象。另一方面,轉發機制將不同的功能分配給不同的對象。它把大的問題分解成小的對象,但是通過對消息發送者透明來把這些對象關聯起來。

代理對象

轉發不僅模仿多繼承,它也使開發輕量級的代表或者“覆蓋”更大量的對象的對象。代理就代表了其他的對象,篩選傳遞給他的消息。
在OC編程語言中的遠程通信中是這樣一個代理。代理需要照顧轉發到遠程接收者的消息的管理細節,確保通過連接的參數值被復制和檢索等等。但它并沒有嘗試去做其他的事情;它不復制遠程對象的功能,只是給給遠程對象一個本地但它并沒有嘗試去做其他的事情;它不復制遠程對象的功能,但只要給遠程對象一個可以在另一個應用程序中接收消息的本地地址。
其他類型的代理對象也可能。例如,假設你有一個對象,操縱大量數據,也許它創建了一個復雜的圖像或讀取磁盤上的文件的內容。設置這個對象是費時的,所以你喜歡懶加載它,當它真正需要的時候或當系統資源暫時閑置的時候。同時,你需要至少一個占位符對象,其他對象在應用程序正常運行。
在這種情況下,你可以創建一個輕量級的不完整的對象替代他。這個對象可以做到一些相對的事情,比如說回答關于數據的問題,但是大多數情況下,它僅僅為一個大對象占位置,當時間到了,轉發消息給它。這個代理的forwardInvocation:方法第一次接收到目的地為另一個對象的消息,他會確定這個對象是否存在,如果不存在就創建它。所有的大對象的消息都是通過代理,就程序的其他部分來說,代理和大對象是一樣的。

轉發和繼承

雖然轉發模擬繼承,但是NSObject類從來不會混淆兩者。像respondsToSelector: 和isKindOfClass:這樣的方法只查看結構,從來不在轉發鏈上。例如,如果一個戰士對象被問到它是否會對談判信息作出反應:
if ( [aWarrior respondsToSelector:@selector(negotiate)] )
答案是不會,即使在某種意義上它可以通過轉發給一個外交官沒有錯誤地接收談判消息,并響應它,
在大多數情況下,不是正確答案。但也有可能不是。如果你使用轉發來設置代理對象或者擴展一個類的功能,轉發機制可能是像繼承一樣透明。如果你想你的對象像他們真正繼承他們轉發消息的對象的行為一樣,你需要在respondsToSelector: 和isKindOfClass:中重新實現你的轉發算法。

- (BOOL)respondsToSelector:(SEL)aSelector
{if ( [super respondsToSelector:aSelector] )return YES; else { } return NO; }

除了respondsToSelector: 和isKindOfClass:方法之外,instancesRespondToSelector:方法中也應該復制轉發算法。如果使用協議,conformstoprotocol:方法也應該被添加到列表中。同樣,如果一個對象轉發任何它接收到的遠程消息,它應該有一個可以返回最終響應轉發消息的methodsignatureforselector:的該寫版。例如,如果一個對象能夠將消息轉發給它的代理,你會實現methodsignatureforselector:如下:

- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector 
{NSMethodSignature* signature = [super methodSignatureForSelector:selector];if (!signature) {signature = [surrogate methodSignatureForSelector:selector];}return signature; }

你可能會考慮將轉發算法封裝到某個地方,讓所有方法包括forwardInvocation:調用他。
注意:這是一門先進的技術,僅僅是用于沒有別的解決方案。不是作為繼承的替代品。如果你必須使用這個技術,確保你對轉發消息的類和要轉發的類的行為有充分的了解。

類型編碼

為了幫助運行時系統,編譯器將每個方法中的返回和參數類型進行編碼,并將該字符串與該方法選擇器關聯。在其他情況下,編碼體系也是很有用的,所以編碼體系是帶有@encode()編譯指令的工公共的可用的。當給一個指定類型,@encode()返回指定的類型的字符串編碼。這個類型可以是任何類型,可以是基本類型,如int型指針,可以是一個標記結構或聯合,或類名,可以被C語言的sizeof()運算符作為參數使用。
下面的表格列出了編碼類型。注意當對一個對象歸檔或者分發時,他們中的許多代碼與你使用的代碼重疊。然而,這些列表中的編碼在你歸檔的時候不能使用他們,你可能想要在歸檔使用那些不是@encode()生成的代碼。


編碼類型


重要提示:OC不支持long double類型。@encode(long double)返回跟編碼double一樣返回d。
數組類型的編碼是包括方括號在內。數組中的元素數目在打開括號之后立即指定,在數組類型之前。例如,一個指向12個float類型的數組將被編碼成:
[12^f]
結構體在大括號內定義,聯合體在遠括號內定義。結構體的標簽首先被列出,然后一個等號和結構域的編碼順序列出。例如下面這個結構體:

typedef struct example {id   anObject; char *aString; int anInt; } Example;

將會編碼成
{example=@*i}
如果定義類型為(Example)或者(example)經過@encode()將會得到相同的編碼結果。結構指針的編碼攜帶相同數量的結構域的信息:
^{example=@*i}
然而間接尋址去除了內部類型的詳細描述
對象被視為結構。例如,通過NSObject類名稱@ encode()方產生這種編碼:{NSObject=#}
一個類只聲明一種isa指針變量
注意:當他們在協議中聲明方法的時候,即使@encode()命令不返回他們,運行時系統使用下表中的補充的編碼。

聲明屬性

當編譯器遇到屬性聲明,它生成與外圍類,分類和協議相關的描述性元數據。你可以使用支持通過名字查看類,分類,協議中的屬性的方法來查看這個元數據,獲得這個屬性的@encode字符串類型,復制成一個C語言字符串數組屬性屬性列表。聲明屬性的列表可用于每個類和協議。

屬性類型和方法

屬性結構定義一個屬性描述符的不透明句柄。

typedef struct objc_property *Property;

你可以使用class_copyPropertyList和protocol_copyPropertyList分別檢索與類,加載分類和協議相關的屬性數組:

objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)

如下例所示:

@interface Lender : NSObject { float alone; } @property float alone; @end

你可以得到他的屬性列表:

id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);

你可以使用property_getName函數發現屬性的名稱

const char *property_getName(objc_property_t property)

你可以在一個類或協議中指定一個名字,可以使用class_getProperty和protocol_getProperty分別獲得引用。

objc_property_t class_getProperty(Class cls, const char *name)objc_property_t protocol_getProperty(Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty)

你可以使用property_getAttributes這個函數去獲得屬性的名字和編碼字符串。了解編碼類型字符串詳情,看類型編碼,了解字符串詳情,看屬性字符串類型和屬性描述的例子:

const char *property_getAttributes(objc_property_t property)

把這些放在一起,你可以使用下面的代碼打印一個類的所有屬性的列表:

id LenderClass = objc_getClass("Lender");
unsigned int outCount, i;objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount); for (i = 0; i < outCount; i++) { objc_property_t property = properties[i]; fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property)); }

屬性類型字符串

你可以使用property_getAttributes這個函數去獲得屬性的名字和編碼字符串,和一些其他屬性。
字符串以T打頭后面跟著編碼類型和逗號,結束是以V打頭加上返回實例變量的名字。在兩者中間以逗號隔開。
以下是聲明類型屬性編碼


屬性編碼

下面的表展示了相同的屬性聲明和property_getAttributes:返回對應的字符串:


圖1

圖2

?

轉載于:https://www.cnblogs.com/akiha/p/5747843.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457465.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457465.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457465.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Java】synchronized關鍵字筆記

Java Synchronized 關鍵字 壹. Java并發編程存在的問題 1. 可見性問題 可見性問題是指一個線程不能立刻拿到另外一個線程對共享變量的修改的結果。 如&#xff1a; package Note.concurrency;public class Demo07 {private static boolean s true;public static void mai…

sql語句分析是否走索引_MySql 的SQL執行計劃查看,判斷是否走索引

在select窗口中&#xff0c;執行以下語句&#xff1a;set profiling 1; -- 打開profile分析工具show variables like %profil%; -- 查看是否生效show processlist; -- 查看進程use cmc; -- 選擇數據庫show PROFILE all; -- 全部分析的類型show index from t_log_account; ##查看…

SQL Server-數據類型(七)

前言 前面幾篇文章我們講解了索引有關知識&#xff0c;這一節我們再繼續我們下面內容講解&#xff0c;簡短的內容&#xff0c;深入的理解&#xff0c;Always to review the basics。 數據類型 SQL Server支持兩種字符數據類型&#xff0c;一種是常規&#xff0c;另外一種則是Un…

【隨記】SQL Server連接字符串參數說明

廢話不多說&#xff0c;請參見 SqlConnection.ConnectionString 。 轉載于:https://www.cnblogs.com/xiesong/p/5749037.html

【設計模式 00】設計模式的六大原則

設計模式的六大原則 參考&#xff1a; 設計模式六大原則 1. 單一職責原則 一個類只負責一個明確的功能 優點&#xff1a; 降低類的復雜度&#xff0c;提高代碼可讀性和可維護性降低變更時對其他功能的影響 2. 里氏替換原則 **原則一&#xff1a;**若 o1 是 C1 的一個實例化…

pb retrieve時停止工作_大佬們掛在嘴邊的PE、PB是什么?

在緊鑼密鼓地準備科創50ETF的發行工作間隙&#xff0c;今天小夏先帶你讀懂最簡單的PE、PB估值指標這兩大指標。01、什么是PE&#xff08;市盈率&#xff09;PE&#xff0c;也就是市價盈利比率&#xff0c;簡稱市盈率。市盈率是指股票價格與每股收益&#xff08;每股收益&#x…

EF CodeFirst 如何通過配置自動創建數據庫當模型改變時

最近悟出來一個道理&#xff0c;在這兒分享給大家&#xff1a;學歷代表你的過去&#xff0c;能力代表你的現在&#xff0c;學習代表你的將來。 十年河東十年河西&#xff0c;莫欺少年窮 學無止境&#xff0c;精益求精 本篇為進階篇&#xff0c;也是彌補自己之前沒搞明白的地方,…

對AutoIt中控件和窗口的理解

經過嘗試&#xff0c;對AutoIt中Control和Window有了新的認識&#xff0c;分享一下 1.Control 現在我想對一個WinForm架構的應用程序進行自動化操作&#xff0c;得到控件Advanced Mode屬性為[Name:XXX]。 然而在該窗口中有多個相同屬性的Control&#xff0c;而依該屬性只能操作…

【設計模式 01】簡單工廠模式(Simple factory pattern)

簡單工廠模式 可以根據參數的不同返回不同類的實例 參考&#xff1a; CSDN|簡單工廠模式 簡單工廠通過傳給工廠類的參數的不同&#xff0c;返回不同的對象&#xff0c;包括三部分組成&#xff1a; 具體的”產品“工廠類&#xff08;實例化并返回”產品“&#xff09;客戶端&am…

[Hadoop]MapReduce多路徑輸入與多個輸入

1. 多路徑輸入 FileInputFormat是所有使用文件作為其數據源的 InputFormat 實現的基類&#xff0c;它的主要作用是指出作業的輸入文件位置。因為作業的輸入被設定為一組路徑&#xff0c; 這對指定作業輸入提供了很強的靈活性。FileInputFormat 提供了四種靜態方法來設定 Job 的…

pvrect r語言 聚類_R語言實現KEGG通路富集可視化

用過KEGG的朋友應該都很熟悉里面的通路地圖。你是否想過如果自己可以控制通路圖將自己的基因繪制在一個通路圖中&#xff0c;那么今天給大家介紹一個新推出的Bioconductor軟件包pathview。這個包可以進行KEGG富集分析。首先&#xff0c;我們不耐煩的介紹下Bioconductor包的安裝…

【設計模式 02】策略模式( Strategy)

策略模式 參考&#xff1a; CSDN | 策略模式百家號 | 策略模式 如果某個系統需要不同的算法&#xff08;如超市收銀的優惠算法&#xff09;&#xff0c;那么可以把這些算法獨立出來&#xff0c;使之之間可以相互替換&#xff0c;這種模式叫做策略模式&#xff0c;它同樣具有三個…

PL/SQL復合變量

復合變量可以將不同數據類型的多個值存儲在一個單元中。由于復合類型可以由用戶自己根據需要定義其結構&#xff0c;所以復合數據類型也稱為自定義數據類型。在PL/SQL中&#xff0c;使用%TYPE聲明的變量類型與數據表中字段的數據類型相同&#xff0c;當數據表中字段數據類型修改…

Android中使用am命令實現在命令行啟動程序詳解

在Android中&#xff0c;除了從界面上啟動程序之外&#xff0c;還可以從命令行啟動程序&#xff0c;使用的是命令行工具am. 復制代碼代碼如下:usage: am [subcommand] [options] start an Activity: am start [-D] -D: enable debugging send a broadcast Intent: am br…

用Visual Studio 2019連接 WSL來編譯調試C/C++項目

因為有作業要在Linux環境下寫&#xff0c;用虛擬機直接卡成PPT&#xff0c;VS code又不會調試&#xff0c;就搞一下VS 2019吧。 環境 windows 10 WSL(Ubuntu 18.04.4) Visual Studio Community 2019 Linux 里要有C/C環境&#xff08;gcc等&#xff09;VS要有 適用于 Linux…

node.js Websocket消息推送---GoEasy

Goeasy, 它是一款第三方推送服務平臺&#xff0c;使用它的API可以輕松搞定實時推送&#xff01;個人感覺goeasy推送更穩定&#xff0c;推送速度快&#xff0c;代碼簡單易懂上手快瀏覽器兼容性&#xff1a;GoEasy推送支持websocket 和polling兩種連接方式&#xff0c;從而可以支…

git 移動分支指針_理解git 中的HEAD指針branch指針

HEAD指針使用git checkout 來移動HEAD指針&#xff0c;移動的對象可以是分支指針也可以是快照。HEAD指針可以指向快照也可以指向branch。當指向branch時提交后會和branch指針一起向后移動&#xff0c;當不指向branch提交時時則會在一個detached狀態。分支(branch)指針使用git b…

應用程序域

好文鏈接 使用.NET建立的可執行程序 .exe&#xff0c;并沒有直接承載到進程當中&#xff0c;而是承載到應用程序域&#xff08;AppDomain&#xff09;當中。應用程序域是.NET引入的一個新概念&#xff0c;它比進程所占用的資源要少&#xff0c;可以被看作是一個輕量級的進程。 …

【設計模式 03】裝飾模式——俄羅斯套娃?

裝飾模式(俄羅斯套娃&#xff1f;) 裝飾模式&#xff1a;動態的給某些對象添加額外的功能 參考&#xff1a; 簡書 | 裝飾模式 博客園 | 簡說設計模式——裝飾模式 博客園 | 裝飾器模式 Decorator 結構型 設計模式 (十) 什么是裝飾模式 裝飾模式也叫裝飾器模式&#xff0c;p…

系統移植的四大步驟

最近在學習系統移植的相關知識&#xff0c;在學習和調試過程中&#xff0c;發現了很多問題&#xff0c;也解決了很多問題&#xff0c;但總是對于我們的開發結果有一種莫名其妙的感覺&#xff0c;糾其原因&#xff0c;主要對于我們的開發環境沒有一個深刻的認識&#xff0c;有時…