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小时内与您取得联系。