TML5練習:自定義班級對象,至少三種形式
自定義班級對象 至少三種形式
包含屬性:班級名稱(name)、班級女生人數(gnum)、班級男生人數(bnum)、班級所屬學院(Class-owned)
包含方法:班級人數總人數(sum,要求在瀏覽器中以警告對話框的形式彈出.alert)、班級重命名(rename,要求彈出輸入框。prompt)
1.無參構造函數
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<Script language="javascript">
function Classes() {
//window.document.write("constructor()<br>");
}
var classes = new Classes();
//定義屬性
classes.name = "17軟件3班";
classes.gnum = 23;
classes.bnum = 25;
classes.Class_owned = "大數據";
//定義方法
classes.sum = function() {
alert(classes.gnum+classes.bnum);
};
classes.rename = function(){
var MyStr = prompt("請輸入名稱");
alert("班級新名稱是:"+MyStr);
};
//獲取構造函數
//window.document.write(classes.constructor + "<br/>");
//window.document.write(classes.name + "," + classes.sum + "<br/>");
//classes.sum();
//classes.name();
</Script>
<p><a href=# onClick="classes.sum()">班級總人數</a></p>
<p><a href=# onClick="classes.rename()">班級重命名</a></p>
</body>
</html>
2.有參數構造函數
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script language=JavaScript>
function Classes(name, gnum, bnum, Class_owned){
this.name = name;
this.gnum = gnum;
this.bnum = bnum;
this.Class_owned = Class_owned;
this.sum = function(){
alert(this.gnum+this.bnum);
}
this.rename = function(){
var MyStr = prompt("請輸入名稱");
alert(MyStr);
}
}
var classes = new Classes("17軟件3班", 23, 25, "大數據");
//classes.sum();
//classes.rename();
</script>
<p><a href=# onClick="classes.sum()">班級總人數</a></p>
<p><a href=# onClick="classes.rename()">班級重命名</a></p>
</body>
</html>
3.Object方法
掌握jvm 字節碼,最關鍵的是學習class文件格式以及字節碼指令集等細節,今天我們來學習class字節碼文件格式(jdk8版本)。
Java代碼經過javac編譯器編譯成class文件,JVM虛擬機讀取class文件執行其中的代碼。
通過JVM虛擬機規范,實現了jvm跨平臺、跨語言的能力,JVM規范中非常重要的一部分就是class字節碼文件格式。
class文件的整體結構如下圖所示,其中u1,u2,u4分別表示1個、2個、4個字節長度的無符號數據,無符號byte數據按照具體的場景可以用來表示數字、字符等。 結構中還可以使用復合結構,比如cp_info, cp_info結構也會在規范中進行定義。
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
魔法字符串,固定為0xCAFEBABE
分別是class文件的小版本號和大版本號,jvm規范要求運行的jvm版本必須大于等于(更嚴格說是能支持,不過目前大于等于即可)class文件的major_version才能運行,否則拋出異常。
常量池數量,是下面的常量池表的長度加一,因為index=0的常量引用沒有使用。
常量池表,每個常量池的結構cp_info如下,常量池可以表示字符串常量、類名、接口名、方法等信息,這些常量池會在class文件中其他地方進行引用(比如字段中字段類型、字段名等)。 常量通過index進行引用,常量之間也可以通過index進行引用。
cp_info中的tag字段用來標識當前的常量類型,不同的常量類型有不同的子結構,然后就可以用具體的結構來解析info[]這個byte數組。 常量的結構有,
cp_info {
u1 tag;
u1 info[];
}
Constant type | tag value |
CONSTANT_Class | 7 |
CONSTANT_Fieldref | 9 |
CONSTANT_Methodref | 10 |
CONSTANT_InterfaceMethodref | 11 |
CONSTANT_Integer | 3 |
CONSTANT_Float | 4 |
CONSTANT_Long | 5 |
CONSTANT_Double | 6 |
CONSTANT_NameAndType | 12 |
CONSTANT_Utf8 | 1 |
CONSTANT_MethodHandle | 15 |
CONSTANT_MethodType | 16 |
CONSTANT_InvokeDynamic | 18 |
我們提前查看一下各個常量類型的結構,給后面介紹Field, Method做鋪墊。
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
CONSTANT_Class_info表示類或接口
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}
tag: 是CONSTANT_Class對應的值(7) name_index: name_index是這個類或接口的類名的字符串常量的index
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
字段引用、方法引用、接口方法引用這三個結構比較類似,都是各自的tag以及class_index和name_and_type_index
class_index: 這個字段、方法所在類的class的常量的index
name_and_type_index: 這個字段的名稱和類型結構常量CONSTANT_NameAndType_info的index。name分別是字段名和方法名,類型是字段、方法的descriptor描述符。
字符串常量結構
string_index: 指向CONSTANT_Utf8_info的index
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
整數和浮點數常量結構,對應的數值占用4個字節。
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
這兩個常量結構分別存儲long和double類型的數值,大小占用8個字節 high_bytes和low_bytes分別表示高位和低位的數據,以long為例,對應值為((long) high_bytes << 32) + low_bytes
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_NameAndType_info常量用來表示名稱和類型,在前面的CONSTANT_Fieldref_info, CONSTANT_Methodref_info, CONSTANT_InterfaceMethodref_info 常量中有使用,結構如下
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
name_index: 指向對應名稱的utf8常量的CONSTANT_Utf8_info的index descriptor_index: 指向類型描述符的CONSTANT_Utf8_info的index。
在jvm中,數據分為primitive type(基本類型,比如int, long)和reference type(引用類型),類型的描述符規則如下
類型 | 描述符 |
byte | B |
char | C |
double | D |
float | F |
int | I |
long | J |
short | S |
boolean | Z |
reference,引用類型 | LClassName; |
數組 | [ |
引用類型的ClassName是/間隔的字符串,比如java.lang.String的描述符為Ljava/lang/String; 數組是在對應的類型前加[,比如int[]描述符為[I, String[]描述符為[Ljava/lang/String;, 多維數組距離 int[][]描述符為[[I
Field Descriptor是對應字段的類型的描述符 Method Descriptor為( {ParameterDescriptor} ) ReturnDescriptor,比如public String test(int a, Long b)的方法描述符為(ILjava/lang/Long)Ljava/lang/String;,如果返回值是void,則使用V
CONSTANT_Utf8_info常量存儲utf8編碼的字符串內容,包含一個字符串長度字段和對應長度的byte數組。
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
access_flags用來表示當前類的一些bit信息(類似bitmap),這樣用2個字節的空間就可以表示16個標記信息。
Flag Name | Value | 表頭 |
ACC_PUBLIC | 0x0001 | 表示當前類/接口是否是public |
ACC_FINAL | 0x0010 | 是否聲明了final |
ACC_SUPER | 0x0020 | 都是true, 為了兼容舊版本的字節碼的標記 |
ACC_INTERFACE | 0x0200 | 是否是接口 |
ACC_ABSTRACT | 0x0400 | 是否是抽象類,接口也是抽象類 |
ACC_SYNTHETIC | 0x1000 | 表示不是代碼中生成的類,比如jdk為實現lambda表達式在運行時生成的一些類 |
ACC_ANNOTATION | 0x2000 | 是否是@interface這樣的注解類 |
ACC_ENUM | 0x4000 | 是否枚舉類 |
Fields是field_info的數組,每個field_info結構如下。
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
access_flags: 字段的access_flags,和class的access_flags類似,用來描述字段的public,private,volatile等等標識信息。
Flag Name | Value | 描述 |
ACC_PUBLIC | 0x0001 | 是否是public字段 |
ACC_PRIVATE | 0x0002 | 是否是private字段 |
ACC_PROTECTED | 0x0004 | 是否是static字段 |
ACC_STATIC | 0x0008 | 是否是static字段 |
ACC_FINAL | 0x0010 | 是否是final字段 |
ACC_VOLATILE | 0x0040 | 是否是volatile字段 |
ACC_TRANSIENT | 0x0080 | 是否是transient字段 |
ACC_SYNTHETIC | 0x1000 | 單元格 |
ACC_ENUM | 0x4000 | 單元格 |
name_index: 字段名稱的CONSTANT_Utf8_info常量index descriptor_index: 字段類型描述符的CONSTANT_Utf8_info常量index attributes_count: 字段的屬性數量 attributes: 字段的屬性,結構為attribute_info,比如ConstantValue,描述常量字段的常量值,屬性的結構稍后介紹。
類中所有的方法包括構造函數(<init>)、靜態初始化方法(<clinit>),都使用method_info結構,在一個類中,方法名稱和方法簽名聯合起來必須唯一
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
access_flags: 方法的標識數據,包括public, private, synchronized等等信息
Flag Name | Value | 描述 |
ACC_PUBLIC | 0x0001 | public方法 |
ACC_PRIVATE | 0x0002 | private方法 |
ACC_PROTECTED | 0x0004 | protected方法 |
ACC_STATIC | 0x0008 | static方法 |
ACC_FINAL | 0x0010 | final方法 |
ACC_SYNCHRONIZED | 0x0020 | synchronized方法(方法維度的synchronized聲明,不同于synchronized代碼塊的monitor_enter和monitor_exit) |
ACC_BRIDGE | 0x0040 | 是否是transient字段 |
ACC_VARARGS | 0x0080 | 有可變參數的方法 |
ACC_NATIVE | 0x0100 | native方法 |
ACC_ABSTRACT | 0x0400 | 抽象方法 |
ACC_STRICT | 0x0800 | 浮點數模式是FT-strict的,這個很少見 |
ACC_SYNTHETIC | 0x1000 | 是否是合成方法,即不再源代碼中的方法 |
name_index: 指向方法名的CONSTANT_Utf8_info常量 descriptor_index: 指向方法描述符的CONSTANT_Utf8_info常量 attributes_count: 方法的屬性數量 attributes[]: 方法的各個屬性,其中比較關鍵的是名字為Code的屬性,包含的是方法體的字節碼指令。
Attributes屬性在classfile, field_info, method_info中都有使用,結構如下
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
attribute_name_index: 指向屬性的名稱的CONSTANT_Utf8_info常量 attribute_length: 屬性信息的字節長度,即info的長度 info[]: 屬性的具體信息,每種屬性有自己的結構
屬性有ConstantValue,Code,StackMapTable,Exceptions,BootstrapMethods等等很多種屬性,我們這里重點介紹一下ConstantValue和Code。
常量值屬性用來表示常量字段的常量值,數值(int,long,float等)和字符串字段能夠聲明成常量。
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
attribute_name_index: 指向"ConstantValue"的CONSTANT_Utf8_info attribute_length: 2,因為constantvalue_index是兩個byte長度的index constantvalue_index: 指向具體的常量池中的常量,按照類型不同分為CONSTANT_Long,CONSTANT_Float,CONSTANT_Double,CONSTANT_Integer(int, short, char, byte, boolean都用CONSTANT_Integer),CONSTANT_String,
Code屬性用來表示方法體中的代碼字節碼。
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
attribute_name_index: 指向"Code"的CONSTANT_Utf8_info常量 attribute_length: 后面所有的字段信息的字節數 max_stack: 方法的字節碼指令執行過程中需要的操作數棧的最大棧層數,關于方法字節碼指令的執行,在字節碼指令文章中進行介紹。 max_locals: 方法的字節碼指令執行過程中需要的本地變量表的最大長度(注意局部變量表的元素長度是4字節,long和double變量在局部變量表中占兩個位置) code_length: 方法體的字節碼的長度 code[]: 方法體的字節碼 exception_table_length: 異常表的長度 exception_table[]: 異常表數組,每個異常表包含start_pc,end_pc,handler_pc,catch_type。pc是指code[]數組中的索引,也就是從code[]字節碼數組start_pc(包含)到end_pc(不包含)中的字節碼執行時出現catch_type(指向異常類的CONSTANT_Class_info常量)異常,則轉到code[]的handler_pc位置來處理異常。 attributes_count: Code屬性的數量 attributes[]: Code屬性數組,比如LineNumberTable,LocalVariableTable, LocalVariableTypeTable, StackMapTable
其他的屬性可以參考jvm規范
假如我們現在有一個class文件,想去查看其中的Java源代碼,該如何實現呢?有如下幾種方法。
javap是jdk里自帶的反編譯工具,可以打印出更加可讀的class字節碼信息。
javap -c -cp /Users/liuzhengyang/Code/work/code-test/target/classes/ test.Test
Compiled from "Test.java"
public class test.Test {
public test.Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public java.lang.String hello();
Code:
0: ldc #2 // String hello world
2: areturn
}
javap參數說明
參數 | 說明 |
-cp | 指定classpath, javap需要到classpath中尋找class文件 |
-p | 默認情況下javap不打印出private的方法、字段,通過-p可以打印全部信息 |
-c | 默認情況下javap不打印出方法的body字節碼,通過-c可以打印 |
-v | 打印最全的信息,包括常量池、方法stack size、方法本地變量表等等 |
把class文件拖動到IDEA中即可查看到反編譯的java代碼結果,相比javap更加易讀。
如果要查看運行中的程序中使用到的代碼,可以使用arthas的[jad](https://arthas.aliyun.com/doc/jad.html)命令。
更詳細的資料包括java語言規范、java虛擬機規范可以在[Java Language and Virtual Machine Specifications](https://docs.oracle.com/javase/specs/index.html)中找到
本篇文章介紹了class文件的結構,包括常量池、字段、方法、屬性等,詳細了解了每個數據的結構,最后了解查看class文件的幾種方式。
屬性是為HTML元素提供的附加信息。
為相同的HTML元素指定不同的屬性,會呈現不同的功能或效果。
舉個例子:
比如我們在上一篇中練習過的<a></a>標簽構成的超鏈接元素中有一個href屬性,這個屬性指定的是點擊后跳轉的頁面地址,相同的<a>標簽改變href屬性就能跳轉不同的頁面。例如
<a href="https://www.bilibili.com/read/cv2720755">殲-20戰斗機</a>
<a href="http://mil.chinanews.com/mil/hd2011/2014/03-06/315569.shtml">殲-20戰斗機</a><!-- 注釋 看起來一樣的超鏈接元素因為href屬性不同,打開的頁面也不同。-->
小伙伴們自己寫的時候要注意使用半角符號,不然不能正確打開鏈接。
超鏈接元素中還有一個控制鏈接頁面打開的屬性叫做target,是用來控制新打開頁面窗口的位置。下面我們就看看target屬性為_blank和_parent的情況下的不同。例如
<a href="https://www.bilibili.com/read/cv2720755" target="_blank">殲-20戰斗機</a>
<a href="http://mil.chinanews.com/mil/hd2011/2014/03-06/315569.shtml" target="_parent">殲-20戰斗機</a><!-- 注釋 看起來一樣的超鏈接元素因為target屬性不同,打開的頁面所在窗口不同。-->
測試后,target="_blank"時,新頁面在測試頁面窗口旁邊新建一個窗口打開。
target="_parent"時,新頁面在原有測試頁面窗口中打開。
如圖所示:
左邊為_blank,右邊為_parent,點擊左邊鏈接后,新窗口在原有窗口旁邊打開。如下圖:
點擊右側
新頁面在原窗口處打開。
<a>標簽的target屬性還有_self、_top這樣的屬性,感興趣的小伙伴可以自行測試。
一般HTML元素的通用屬性有:class 、id 、style 、title這四類,其中class 、id 、style這三個屬性會在CSS的講解中詳細學習。
下面我們通過練習來看看title屬性的作用。
HTML元素屬性使用練習1
NO.1: title
title屬性用于顯示元素的額外信息使用。示例代碼如下:
<!DOCTYPE HTML>
<html>
<head>
<title>第一個網頁</title>
</head>
<body>
<h1>第一個網頁</h1><hr>
<a href="https://www.bilibili.com/read/cv2720755" target="_blank" title="中國最先進戰斗機">殲-20戰斗機</a>
</body>
</html>
效果如圖:當鼠標移動到超鏈接上時,"中國最先進戰斗機"的說明就出現在下側。
NO.2:href/src/url
這三個屬性雖然寫法不同,但都是為元素指定路徑使用的。不屬于通用屬性。
例如<a>標簽中指定鏈接路徑使用的是href,而<img>標簽中導入圖片的路徑是src,url在css中也常用來引入鏈接。具體練習大家可以翻看《HTML中的元素使用方法2——零基礎自學網頁制作》一文。
這里要介紹的是關于網頁中的路徑的兩個重要概念:絕對路徑、相對路徑。
絕對路徑是指文件在硬盤上真正存在的路徑。
相對路徑就是相對自己的目標文件的位置。
怎么理解這兩個概念呢?舉個例子:
如果我們要在"第一個頁面.html"中顯示一張圖片image1.jpg,它們都在我的"D盤/零基礎自學網頁制作"這個文件夾中。如圖:
如果用絕對路徑導入寫法是這樣的:
<img src="file:///D:/零基礎自學網頁制作/image1.jpg"/>
相對路徑這樣寫:
<img src="image1.jpg"/>
大家觀察一下,也看出了絕對路徑與相對路徑的區別了。
另外,這樣的鏈接也屬于絕對路徑:href="https://www.bilibili.com/read/cv2720755"
那么什么時候使用相對路徑什么時候使用絕對路徑呢?這個問題我會在明天深入為大家講解,這涉及到網頁或網站上傳服務器的問題。
做教程確實是沒什么人看,但是我依然會堅持,我是一名高校教師(認證資料等疫情結束后去辦公室拍攝上傳吧),把自己的知識寫出來對自己來說是一個提高,也把原來很多常用卻不甚了然的概念再次打磨清晰是我最大的收獲。本篇教程針對完全沒有基礎的網頁制作學習者,利用碎片時間學習,只要我們堅持,必然可以完成網頁制作的學習,為未來學習更加復雜的內容打下基礎!
喜歡的小伙伴請關注我,閱讀中遇到任何問題請給我留言,如有疏漏或錯誤歡迎大家斧正,不勝感激!
HTML序章(學習目的、對象、基本概念)——零基礎自學網頁制作
HTML是什么?——零基礎自學網頁制作
第一個HTML頁面如何寫?——零基礎自學網頁制作
HTML頁面中head標簽有啥用?——零基礎自學網頁制作
初識meta標簽與SEO——零基礎自學網頁制作
HTML中的元素使用方法1——零基礎自學網頁制作
HTML中的元素使用方法2——零基礎自學網頁制作
HTML元素中的屬性1——零基礎自學網頁制作
HTML元素中的屬性2(路徑詳解)——零基礎自學網頁制作
使用HTML添加表格1(基本元素)——零基礎自學網頁制作
使用HTML添加表格2(表格頭部與腳部)——零基礎自學網頁制作
使用HTML添加表格3(間距與顏色)——零基礎自學網頁制作
使用HTML添加表格4(行顏色與表格嵌套)——零基礎自學網頁制作
16進制顏色表示與RGB色彩模型——零基礎自學網頁制作
HTML中的塊級元素與內聯元素——零基礎自學網頁制作
初識HTML中的<div>塊元素——零基礎自學網頁制作
在HTML頁面中嵌入其他頁面的方法——零基礎自學網頁制作
封閉在家學網頁制作!為頁面嵌入PDF文件——零基礎自學網頁制作
HTML表單元素初識1——零基礎自學網頁制作
HTML表單元素初識2——零基礎自學網頁制作
HTML表單3(下拉列表、多行文字輸入)——零基礎自學網頁制作
HTML表單4(form的action、method屬性)——零基礎自學網頁制作
HTML列表制作講解——零基礎自學網頁制作
為HTML頁面添加視頻、音頻的方法——零基礎自學網頁制作
音視頻格式轉換神器與html視頻元素加字幕——零基礎自學網頁制作
HTML中使用<a>標簽實現文本內鏈接——零基礎自學網頁制作
*請認真填寫需求信息,我們會在24小時內與您取得聯系。