Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
JVM 的類加載子系統(Class Load SubSystem) 是 JVM 架構的第一個重要階段,我們最常見的 JVM 架構簡圖是下面這樣事兒的,只瞅一眼就跟明鏡兒似的,類加載子系統的責任那是明明白白的,負責從文件系統或網絡中加載 class 文件到 JVM 運行時數據區。
JVM 架構簡圖
既然都這么明確了,那只能不繞圈子了,其實類加載子系統還是有點復雜的,并不像上圖那樣跟一個青春妹子一樣單純、可愛、簡單,她的內心你得多少了解點,不然我講不下去了,想留住單純美好時光的肥宅們,可以到此打住了。
類加載子系統雖然只負責將 class 文件加載到 JVM 的運行時數據區,其實她也不管最后能不能執行,反正是符合她的“擇偶”條件就會加載,雖然單純可愛簡單,但是該有的流程還是要有的。
有好事者總結如下:
類加載子系統
還是有點小復雜,但今天不能重點介紹,說多了就沒有距離感了,還是先保留一點單純可愛簡單吧。
接下來說今天要探討的重點:鏈接(Linking)階段的解析過程(Resolution)。
鏈接(Linking)階段分為了三個階段:驗證(Verification)、準備(Preparation)、解析(Resolution)。
驗證階段,簡單來說,確保 class 文件包含的信息是符合當前虛擬機要求的,確保加載類的正確性,確保其不會危害虛擬機的自身安全;這個階段主要包括四種驗證:文件格式驗證、元數據驗證、字節碼驗證、符號引用驗證。
著名的魔數【CAFEBABE】(諧音:咖啡寶貝)就是在這個階段驗證的,凡是 JVM 標準的 class 文件都是以這個魔數開始的,名字聽著就那么個感覺!
準備階段,簡單來說,就是類變量分配內存并且設置該類的默認初始值,也就是零值;比如定義了一個 static 變量 a=1,在這個階段會默認賦值 a=0,在后面的初始化階段會將 a 賦值為 1。
需要注意的是:
1. 這個階段不包含用 final 修飾的 static 變量,因為 final 會在編譯階段分配
2. 這個階段不包含實例變量的分配與初始化,因為它們會在堆區創建對象時初始化
好了,終于到整體了,接下來就是解析(Resolution)階段啦。
解析階段,簡單來說,就是常量池中的符號引用轉換為直接引用的過程,解析的主要是類或接口、字段、類方法、接口方法、方法類型等,對應到常量池中的CONSTANT_Class_info、 CONSTANT_Fieldref_info、 CONSTANT_Methodref_info 等。
千呼萬喚,終于出來了,接下來就是本篇核心知識點了:符號引用、直接引用了。
解析階段的主要操作是將類常量池中的符號引用替換為直接引用。啥?(黑人問號臉)
符號引用,簡單說,就是一個字符串,這個字符串定義了被引用項的唯一識別信息,根據這個信息可以無歧義地定位到一個類、字段、方法等。
一句話:就是一個唯一標識符
直接引用,簡單說,就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。
一句話:就是一個直接內存地址的表示
符號引用與虛擬機的內存布局無關,引用的目標并不一定加載到內存中,一個 java 類編譯為 class 文件時,java 類并不知道所引用的類的實際地址,因此只能使用符號引用代替。
初始化階段后,已經可以知道被引用項的真實地址(也就是,直接引用)了,解析階段會將常量池內的符號引用替換為直接引用。
各種虛擬機實現的內存布局可能有所不同,但是它們能接受的符號引用都是一致的,因為符號引用的字面量形式明確定義在 Java 虛擬機規范的 Class 文件格式中。
Boss 說太干了,來點實際的,要想成功就得讓我聽懂。
有好事者總結了:
(1)我們先寫個 java 版本的 Hello World 小程序(PS :這個 Boss 再不懂就辭職啦)
public class Hello {
private static int a=1;
public static void main(String[] args) {
System.out.println(a);
}
}
(2)寫完后我們編譯一下,有 IDE 的直接自動編譯,沒有的使用 javac 搞一下
(3)編譯成功后可以找到 Hello.class,哎,對就是這個!
(4)然后在 class 文件所在目錄打開命令行,輸入一個神奇命令:javap -v Hello.class
(5)接下來,見證一下奇跡,找尋一下常量池(Constant Pool)
Boss,請看下圖:
這就是編譯后常量池中定義的符號引用了,看看 Ljava/lang/String; 就是代表 java.lang.String 類。
常量池的符號引用
本著服務 Boss 的宗旨,這么多描述符,鬼知道是怎么回事啊,Boss 教導說,工作要有總結。
那么,好事者又總結了。
JNI 字符描述符是類描述符、方法描述符、字段描述符的具體的實現規則,描述規則如下:
(1)類描述符 : 以 L 開頭,其后跟著該類的全限定名,并將其中中的 “.” 改為 “/” ,最后分號“;”結束
類:Java.lang.String
對應描述符:Ljava/lang/String;
(2)基本類型描述符:基本類型不存在全限定名,故只需要一個符號就可以表達該基本類型
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
(3)字段描述符 :格式為 字段名:類型
int num=3;
字段描述符: num:I
字段名: num
(4)數組描述符 : 原描述符前加一個 [ 表示一維數組,加兩個[[ 表示二維數組
String[][] num=null;
字段描述符:[[Ljava/lang/String;
字段名:num
(5)方法描述符: (第一個參數的字段描述符第二個參數的字段描述符.....)返回類型的描述符
# 示例 1
String test();
方法描述符:()Ljava/lang/String;
方法名:test
# 示例 2
long test(int i, Object c);
方法描述符:(ILjava/lang/Object;)J
方法名:test
# 示例 3
void test(byte[] bytes);
方法描述符:([B)V
方法名:test
Boss 說得對,來個小總結吧,好事者又開始了表演。
感謝以下文章或視頻提供的學習資料,受益匪淺:
內容為學習相關資料后的總結,一字一碼,姑且算是原創吧,歡迎轉載,公眾號或商業轉載請聯系本人。
謝謝各位讀完本文,初涉寫作,內容不佳,敬請見諒,如果對您有幫助,歡迎轉發、評論、關注。
頁
網站是使用HTML等制作的用于展示特定內容相關的網頁集合
網頁是網站中的一“頁”,通常是HTML格式的文件,需要通過瀏覽器來閱讀。
網頁是構成網站的基本元素,它通常由圖片、連接、文字、聲音、視頻等元素組分。一般以.htm或.HTML為后綴名的文件,都是HTML文件。
什么是html
html是超文本標記語言,它是用來描述網頁的一種語言。
1、可以加入圖片、聲音、動畫、多媒體文件等內容。
2、還可以從一盒文件跳轉到另一個文件,與世界各地主機的文件連接。
網頁是由網頁元素組成,這些元素是利用html標簽描述出來的,通過瀏覽器顯示給用戶。
靜/動態區別:
靜態:
XX.htm、xx. Html
區分方式:網頁中數據的提取來源方式
動態:
Xx.jsp、xx.php、xx.asp、xx.cgi
頁面中的數據可以通過和數據庫等其他來源提取
動靜態交互使用
Html語句的語法的基本單位:
標簽、標記
tag<標簽單詞><標簽單詞 屬性名1=”屬性值” 屬性名1=”屬性值”>
多數標簽成對使用,相對少數標簽非成對(獨立)使用<img>獨立使用
<a> ... </a> 制作超級鏈接
1. 創建文本文件
2. 書寫html代碼(標簽)
3. 保存文件
4. 文件名后綴改為.Html或.html
5. 瀏覽器打開以上網頁文件
標簽不能書寫中文,只能是英文
代碼中“空格”為縮進
嵌套
<html>
<head> </head>
<body> </body>
</html>
<font></font>修飾文字
字形face Font size=“1--7”字體大小 color顏色
<em></em>強調,斜體字
<p>段落文字</p>
<img src=”圖片文件名”alt=”xxxxx”width=”像素寬度”height=”像素高度”>
絕對路徑:”file:///D:/html/11.jpg”
相對路徑:”../src/1.html/11.jpg”
<a>超鏈接</a>
頁間跳轉
<a href=”http://www.baidu.com”>文字、圖片</a>
<a href=”../src/1.html”>文字、圖片</a>
頁內跳轉(標簽需要成對出現)href=作為起點name=作為結尾需要去到的地方
<a Href=”#變量名”>....</a>
..................
<a name=”變量名”>xxx</a>
<a href=”..../#t1”
兩者結合使用<a href=”http://www.baidu.com/news/#變量名”>
...............
<a name=”變量名”></a>
“彈幕”滾動標簽
標簽在不同瀏覽器當中打開時的內容是不一樣的
可用GRB單詞進行顏色查找
獨立使用標簽:<img>< hr>< br換行>在需要換行的地方輸入即可
空格在html中作為特殊符號使用:作為分隔符“ ”
Html中漢字不作為標簽符
<;&abc>;作為括號使用
字符集不同會出現亂碼
Align水平對齊屬性;left、right、center
注釋 屏蔽代碼
Dos批處理 在注釋前加上“rem”
Html <!-- 注釋的內容...... - ->
擴展<META>元數據標簽
標簽名稱、獨立使用、主要作用
放在<head></head>中執行 部分功能在瀏覽器打開時就開始工作
Charset 字符集
Set 賦值
Set 集合
Th 保存表格數據的單位,等同于<td>。但自帶居中加粗顯示
Td、th單元格合并:
同行左右單元格合并colspan=”n”
同列上下單元格合并rowspan=”n”
謂操作符,就是用來操作數據值的符號,在JavaScript中包括算術操作符、位操作符、關系操作符和相等操作符。這些操作符可以操作所有類型的數據,比如字符串、數字、布爾值,甚至對象。
所謂一元操作符就是只能對一個數據值進行操作,比如(遞增、遞減)操作符。
遞增、遞減操作符是直接借鑒C語言的,它分前置型和后置型。前置就是操作符在要操作的變量之前,后置在變量之后。
如下示例:
// 前置型
let age=20;
++age; // 遞增
console.log(age); // 結果輸出21
--age;//遞減
console.log(age); // 結果輸出20
如上面例子,age通過++操作符遞增變成21,又通過--操作符遞減變成20;上面的操作等同下面的操作:
// 后置型
let age=20;
age=age + 1; // 加1
age=age -1; // 減1
同理使用后置操作符會得到上面同樣的結果,但是前置和后置有區別。前置操作符在語句被求值以前改變,后置是在語句被求值后改變。通過下面的例子看下其區別:
// 前置
let age=20;
let anotherAge=--age + 5;
alert(age); // 輸出19
alert(anotherAge); // 輸出24
由于前置操作符的優先級和執行語句相等,因此會從左到右依次求值。上面的--age 會先進行遞減操作,再繼續后面的 + 5 運算,所以結果是24。
// 后置時
let age=20;
let anotherAge=age-- + 5;
alert(age); // 輸出19
alert(anotherAge); // 輸出25
但是后置的最終結果卻是25,因為age-- 使用了遞減前的值繼續和后面進行+5運算。
如果使用一個加號或減號時,加號代表正值、減號代表負值。
操作多個數據值,比如加減乘除等:
let a=1,b=2;
let c=a + b; // 加
let d=c - a; // 減
let e=d * b; // 乘
let f=e/d; // 除
注意加減乘除主要用來操作數字類型的數據,如果操作數不是數字類型,會先進性強制轉換再進行計算,這樣結果會不確定。
位操作符,是指按內存中的表示的數值位來操作數值,通俗講就是用來操作二進制的數據。二進制數據都是由0、1組成的,在JavaScript中所有數值都是64位的格式存儲,但位操作符不直接在64位的值上進行計算,會先轉化成32位后再運算。位操作符有以下幾種:
按位非(NOT)
按位非操作符是(~)符號,就是將二進制中每位數值進行反碼操作。其規則如下:
操作符 | 數值 | 結果 |
~ | 1 | 0 |
~ | 0 | 1 |
如下示例:
let a=25;
let b=~a;
alert(b); // 輸出-26
按位與(AND)
使用(&)符號表示,它有2個操作數,當2個數對應的位都是1時返回1,任何一位是0則返回0。如下規則:
數值1 | 操作符 | 數值2 | 結果 |
1 | & | 1 | 1 |
1 | & | 0 | 0 |
0 | & | 1 | 0 |
0 | & | 0 | 0 |
示例:
let a=25 & 3;
alert(a); // 輸出結果是1
按位或(OR)
用(|)符號表示,同樣也是2個操作數。其規則是只要有一位是1其結果就是1,負則結果是0;
數值1 | 操作符 | 數值2 | 結果 |
1 | | | 1 | 1 |
1 | | | 0 | 1 |
0 | | | 1 | 1 |
0 | | | 0 | 0 |
示例:
let a=25 | 3;
alert(a); // 輸出結果是27
按位異或(XOR)
由(^)符號表示,也是操作2個操作數,其當2個操作數的位值相同時返回0,負則返回1。
數值1 | 操作符 | 數值2 | 結果 |
1 | ^ | 1 | 0 |
1 | ^ | 0 | 1 |
0 | ^ | 1 | 1 |
0 | ^ | 0 | 0 |
示例:
let a=25 ^ 3;
alert(a); // 輸出結果是26
左移
使用(<<)兩個小于號表示,這個操作符會將數值每一位向左移動指定位數。如下示例:
let a=2; // 二進制 10
let b=b << 5; // 二進制的 1000000,十進制64
上面,將二進制10向左移動5位,注意左移會多出5個空位,用0來填充,這樣就會得到一個完整的32位二進制數據。
注意,左移不會影響符號位(二進制位中第一位表示數的正負),如-2 向左移5位結果是-64。
有符號的右移
使用(>>)兩個大于號表示,會將每位向右移動指定位數,但保留符號位(即正負號標記)。如下示例:
let a=64; // 二進制 1000000
let b=b >> 5; // 二進制的 10,十進制的2
在移位過程,原數中也會出現空位,只不過這次空位出現在原數值左側、符號位右側。空位使用符號位值填充。
有符號的整數,指32位中前31位表示整數的值,第32位表示數值的符號,0正數,1負數。這個表示符號的位就是符號位。
無符號的右移
使用(>>>)三個大于號表示,這個操作會將所有32位都向右移動。對于正數其結果和有符號的右移一樣,如下示例:
let a=64; // 二進制 1000000
let b=b >>> 5; // 二進制的 10,十進制的2
但是負數就不一樣了,無符號的右移是以0來填充空位,不像有符號右移使用符號位填充。所以其結果相差很大,如下示例:
let a=-64; // 二進制 1111 1111 1111 1111 1111 1111 1100 0000
let b=b >>> 5; // 二進制 0000 0111 1111 1111 1111 1111 1111 1110 ,十進制的134217726
在任何編程語言中,布爾操作符都是非常重要的,它是用來判斷邏輯的關鍵,布爾操作符一共有三種:非(NOT)、與(AND)、或(OR)。
邏輯非
使用(!)感嘆號表示邏輯非,其規則就是:
操作符 | 邏輯值 | 結果 |
! | true | false |
! | false | true |
邏輯與
使用(&&)表示,操作兩個數,如下示例:
let a=ture && false;
其規則如下:
邏輯值1 | 操作符 | 邏輯值2 | 結果 |
ture | && | ture | ture |
ture | && | false | false |
false | && | ture | false |
false | && | false | false |
也就是只有當2個數值都是true時其結果才是true。
邏輯或
使用(||)符號表示,也是有兩個操作數,其示例:
let a=true || false;
規則如下:
邏輯值1 | 操作符 | 邏輯值2 | 結果 |
ture | || | ture | ture |
ture | || | false | ture |
false | || | ture | ture |
false | || | false | false |
也就是2個操作數中有一個true,結果就是true,負則是false。
注意布爾操作符,不僅僅可以操作布爾類型值,對于其它數據類型同樣適用,只不過會先將其它數據類型轉換成布爾值,再進行布爾運算。如下示例:
let a=!1; // 輸出false
let b=!'string'; // 輸出false
let c=1 || 0; // 輸出true
let e=1 && 0;// 輸出false
let d=''&& 2; // 輸出true
關系操作符用來比較2個操作數,有小于(<)、大于(>)、小于等于(<=)和大于等于(>=)。其比較的結果返回一個布爾值,true或false。
如下示例:
let a=5 > 3; // true
let b=5 < 3; // false
同樣,關系操作符也可以適用其它類型的數據,比如字符串比較大小時,會按照字符的編碼大小比較。如下示例:
let a="Brick" < "alphabet"; // true,
上面中因為B字符編碼是66,a的編碼是97,所以返回true。
在編程中,確定2個值是否相等是一個非常重要的操作。在JavaScript中分相等(==)和全等(===)、不等(!=)和不全等(!==)四種。
相等(==)和不相等(!=)
如下示例:
let a=1==1; // true
let b=1==0;// false
let c=1!=1; // false
let d=1!=0; //true
注意相等和不相等的操作前會先對操作性進行強制轉換,如下示例:
let a=true==1; // 先將true轉換成1再比較,結果是true
let b=false==1; // 先將false轉換成0再比較,結果是false
全相等(===)和不全相等(!==)
全等和不全等不同之處是,它在比較數據前,不進行數據類型轉換,是對原始數值比較,所以它的結果更加嚴格準確,如下示例:
let a=1===1; // true
let b=1==='1';// false
let c=1!==1; // false
let d=1!=='1'; //true
注意和之前相等和不相等的例子比較,其結果非常不一樣。
使用(=)表示賦值操作,其作用就是把等號右側的值賦值給左邊的變量或屬性,如下示例:
let a=10; // 給a變量賦值10
如果在等號前面加上其它操作符,就組成了復合型賦值操作,如下示例:
let a=10;
a +=5; // 結果是 15
上面的等同于下面:
let a=10;
a=a + 5; // 結果是 15
當然也可以使用其它操作符,如(*=)、(/=)、(%=)、(-=)、(<<=)等等。
也稱三目運算符,它是一種簡便的條件運算,可以把它看成是if else的簡化,其語法如下:
變量=布爾表達式 ? true_value : false_value
先求出問號前面的布爾表示結果,如果是true,變量使用冒號前面的值,負則使用冒號后面的值。如下示例:
let a=5 > 3 ? '好' : '不好'; // 結果是 '好'
使用(,)符號,表示可以執行多個操作,常用于變量定義或函數參數,如下示例:
var a=0,b=1,c=2; // a、b、c使用逗號隔開
let a,b,c;
// 函數中的參數a、b、c使用逗號隔開
function test(a,b,c){
// 函數主體
}
// 調用函數
test(1,2,3)
本節主要講述了JavaScript中所有的操作符概念,這些都是最基本的知識,需要完全掌握。在平常工作中其中除了位操作符不常用外,其它操作符使用頻率很高,尤其是布爾操作符,算術操作符,比較操作符等。
本篇只是大概講述了操作符的概念和使用方法,還有一些細節沒有講到,作為入門課程已經足夠了,你可以自己搜索每個知識點詳細內容,比如關于二進制數據、位操作、數據類型強制轉換等,這里不再詳細介紹。
《JavaScript 高級程序設計》
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
https://www.w3cschool.cn/javascript/js-operators.html
*請認真填寫需求信息,我們會在24小時內與您取得聯系。