当前位置: 首页 > news >正文

网站建设注意哪些内容石家庄建站培训

网站建设注意哪些内容,石家庄建站培训,河北永生建筑工程网站,海宁网站建设公司推荐文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用#xff0c;聊一下我们常见的一些java语句的特性底层… 文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用聊一下我们常见的一些java语句的特性底层是如何实现。 1. if语句 if语句是我们最常用的判断语句之一它的底层实现原理是什么呢可以通过反编译字节码来分析一下。 假设我们有以下的java代码 public class IfStatement {public static void main(String[] args) {int a 10;if (a 0) {System.out.println(a is positive);} else {System.out.println(a is negative or zero);}} }可以使用javap命令来反编译字节码 javap -c IfStatement.class输出结果如下 public class IfStatement {// 构造方法public IfStatement();Code:0: aload_0 // 将局部变量表中的第0个元素通常是this引用入栈1: invokespecial #1 // 调用父类Object的构造方法4: return // 方法返回// main方法public static void main(java.lang.String[]);Code:0: bipush 10 // 将10压入栈顶2: istore_1 // 将栈顶元素10存入局部变量表的第1个位置3: iload_1 // 将局部变量表的第1个位置的元素10入栈4: ifle 17 // 判断栈顶元素10是否小于等于0如果是则跳转到指令177: getstatic #2 // 获取System类的out字段类型是PrintStream10: ldc #3 // 将字符串a is positive压入栈顶12: invokevirtual #4 // 调用PrintStream的println方法输出字符串15: goto 23 // 无条件跳转到指令2318: getstatic #2 // 获取System类的out字段类型是PrintStream21: invokevirtual #5 // 调用PrintStream的println方法输出局部变量表第1个位置的元素1024: return // 方法返回 }字节码的解析 在main方法中首先将10压入栈顶然后将其存入局部变量表的第1个位置。然后将局部变量表的第1个位置的元素10入栈判断其是否小于等于0如果是则跳转到指令17否则执行下一条指令。在指令7-15中它获取System的out字段将字符串a is positive压入栈顶然后调用println方法输出这个字符串最后无条件跳转到指令23。在指令18-21中它获取System的out字段然后调用println方法输出局部变量表第1个位置的元素10。最后main方法返回。 2. for循环 for循环是我们常用的循环语句之一它的底层实现原理是什么呢我们还是可以通过反编译字节码来分析一下。 假设我们有以下的java代码 public class ForLoop {public static void main(String[] args) {for (int i 0; i 10; i) {System.out.println(i i);}} }可以使用javap命令来反编译字节码 javap -c ForLoop.class这是一个包含for循环的Java类ForLoop的字节码输出下面是中文注释 public class ForLoop {// 构造方法public ForLoop();Code:0: aload_0 // 将局部变量表中的第0个元素通常是this引用入栈1: invokespecial #1 // 调用父类Object的构造方法4: return // 方法返回// main方法public static void main(java.lang.String[]);Code:0: iconst_0 // 将0压入栈顶1: istore_1 // 将栈顶元素0存入局部变量表的第1个位置2: iload_1 // 将局部变量表的第1个位置的元素0入栈3: bipush 10 // 将10压入栈顶5: if_icmpge 19 // 如果局部变量表的第1个位置的元素0大于等于栈顶元素10则跳转到指令198: getstatic #2 // 获取System类的out字段类型是PrintStream11: new #3 // 创建一个StringBuilder类的对象14: dup // 复制栈顶元素此时栈顶有两个相同的StringBuilder对象引用15: invokespecial #4 // 调用StringBuilder类的构造函数初始化对象18: ldc #5 // 将字符串i 压入栈顶20: invokevirtual #6 // 调用StringBuilder的append方法将字符串添加到StringBuilder23: iload_1 // 将局部变量表的第1个位置的元素0入栈24: invokevirtual #7 // 调用StringBuilder的append方法将数字添加到StringBuilder27: invokevirtual #8 // 调用StringBuilder的toString方法将StringBuilder转化为字符串30: invokevirtual #9 // 调用PrintStream的println方法输出字符串33: iinc 1, 1 // 将局部变量表的第1个位置的元素0增加136: goto 2 // 无条件跳转到指令2形成循环39: return // 方法返回LineNumberTable:line 3: 0line 4: 8line 3: 33line 6: 39StackMapTable: number_of_entries 2frame_type 252 /* append */offset_delta 2locals [ int, int ]stack []frame_type 250 /* chop */offset_delta 36 }字节码的解析 可以看到for循环的底层实现是通过if_icmpge指令来实现的。在本例中当i小于10时会执行第8行的输出语句否则会跳转到第39行结束循环。 在main方法中首先将0压入栈顶然后将其存入局部变量表的第1个位置。接下来是一个循环循环条件是局部变量表的第1个位置的元素小于10。在循环体中它首先获取System的out字段然后创建一个StringBuilder对象并初始化然后将字符串i 和局部变量表的第1个位置的元素添加到StringBuilder然后将StringBuilder转化为字符串然后调用println方法输出字符串。在循环体结束时它将局部变量表的第1个位置的元素加1然后无条件跳转到指令2形成循环。当循环结束时main方法返回。 3. while循环 while循环是我们常用的循环语句之一它的底层实现原理是什么呢我们还是可以通过反编译字节码来分析一下。 假设我们有以下的java代码 public class WhileLoop {public static void main(String[] args) {int i 0;while (i 10) {System.out.println(i i);i;}} }可以使用javap命令来反编译字节码 javap -c WhileLoop.class输出结果如下 public class WhileLoop {public WhileLoop();Code:0: aload_01: invokespecial #1 // Method java/lang/Object.init:()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_01: istore_12: iload_13: bipush 105: if_icmpge 198: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;11: new #3 // class java/lang/StringBuilder14: dup15: invokespecial #4 // Method java/lang/StringBuilder.init:()V18: ldc #5 // String i 20: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;23: iload_124: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;27: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;30: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V33: iinc 1, 136: goto 239: returnLineNumberTable:line 3: 0line 4: 2line 5: 8line 6: 33line 5: 36line 8: 39StackMapTable: number_of_entries 2frame_type 252 /* append */offset_delta 2locals [ int, int ]stack []frame_type 250 /* chop */offset_delta 36 }可以看到while循环的底层实现也是通过if_icmpge指令来实现的。在本例中当i小于10时会执行第8行的输出语句否则会跳转到第39行结束循环。 4. switch语句 switch语句是我们常用的分支语句之一它的底层实现原理是什么呢我们还是可以通过反编译字节码来分析一下。 假设我们有以下的java代码 public class SwitchStatement {public static void main(String[] args) {int i 2;switch (i) {case 1:System.out.println(i is 1);break;case 2:System.out.println(i is 2);break;case 3:System.out.println(i is 3);break;default:System.out.println(i is neither 1, 2 nor 3);break;}} }可以使用javap命令来反编译字节码 javap -c SwitchStatement.class输出结果如下 public class SwitchStatement {public SwitchStatement();Code:0: aload_01: invokespecial #1 // Method java/lang/Object.init:()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_21: istore_12: iload_13: tableswitch { // 1 to 31: 282: 403: 52default: 64}28: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;31: ldc #3 // String i is 133: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V36: goto 7140: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;43: ldc #5 // String i is 245: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V48: goto 7152: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;55: ldc #6 // String i is 357: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V60: goto 7164: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;67: invokevirtual #7 // Method java/io/PrintStream.println:()V70: return71: returnLineNumberTable:line 3: 0line 4: 2line 5: 28line 6: 40line 7: 52line 8: 64line 9: 70line 7: 71StackMapTable: number_of_entries 5frame_type 252 /* append */offset_delta 28locals [ int ]frame_type 252 /* append */offset_delta 11locals [ int ]frame_type 252 /* append */offset_delta 12locals [ int ]frame_type 252 /* append */offset_delta 12locals [ int ]frame_type 252 /* append */offset_delta 3locals [ int ]可以看到switch语句的底层实现是通过tableswitch指令来实现的。在本例中当i等于1时会执行第28行的输出语句当i等于2时会执行第40行的输出语句当i等于3时会执行第52行的输出语句否则会执行第64行的输出语句。 5. try-catch语句 try-catch语句是我们常用的异常处理语句之一它的底层实现原理是什么呢我们还是可以通过反编译字节码来分析一下。 假设我们有以下的java代码 public class TryCatchStatement {public static void main(String[] args) {try {int[] arr new int[3];arr[4] 5;} catch (ArrayIndexOutOfBoundsException e) {System.out.println(Array index out of bounds!);}} }可以使用javap命令来反编译字节码 javap -c TryCatchStatement.class输出结果如下 public class TryCatchStatement {public TryCatchStatement();Code:0: aload_01: invokespecial #1 // Method java/lang/Object.init:()V4: returnpublic static void main(java.lang.String[]);Code:0: iconst_01: newarray int3: astore_14: aload_15: iconst_46: iconst_57: iastore8: goto 1911: astore_112: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;15: ldc #3 // String Array index out of bounds!17: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V20: returnException table:from to target type0 8 11 Class java/lang/ArrayIndexOutOfBoundsExceptionLineNumberTable:line 3: 0line 4: 4line 5: 11line 6: 12line 7: 20StackMapTable: number_of_entries 2frame_type 34 /* same */frame_type 1 /* same_locals_1_stack_item */stack [ class java/lang/ArrayIndexOutOfBoundsException ] }可以看到try-catch语句的底层实现是通过异常表来实现的。在本例中当数组下标越界时会执行第12行的输出语句否则会跳转到第20行继续执行。 6. i 和i的字节码 i 和 i 在语义上有些许不同在字节码层面也有所体现。下面是它们的字节码层面的解释 假设 i 是局部变量表的索引为1的变量。 i 的伪字节码 iload_1 // 从局部变量表中加载变量 i 到操作数栈顶 iinc 1 by 1 // 将局部变量表中的变量 i 增加1i 的伪字节码 iinc 1 by 1 // 将局部变量表中的变量 i 增加1 iload_1 // 从局部变量表中加载变量 i 到操作数栈顶可以看到i 与 i 的主要区别在于加载和增加操作的顺序不同。i 是先将 i 加载到操作数栈顶然后再增加 i 的值而 i 是先增加 i 的值然后再将 i 加载到操作数栈顶。这就解释了 i 和 i 在语义上的不同i 是先取值后加1i 是先加1后取值。 7. try-catch-finally 在 Java 字节码中try-catch-finally 结构主要通过异常表Exception Table来实现。Java 字节码并没有专门的指令来表示 try、catch 或者 finally 块。相反它通过在异常表中记录 try 块的开始和结束位置、catch 块的开始位置和要捕获的异常类型以实现异常处理的流程。 下面是一个简单的 try-catch-finally 代码例子 void test() {try {System.out.println(try block);throw new Exception();} catch (Exception e) {System.out.println(catch block);} finally {System.out.println(finally block);} }对应的字节码指令 0: getstatic #2 // 获取 java/lang/System 类的 out 字段是 PrintStream 类型 3: ldc #3 // 将常量池中的 try block 字符串压入栈顶 5: invokevirtual #4 // 调用 PrintStream 类的 println 方法输出字符串 8: new #5 // 创建一个 java/lang/Exception 类的对象 11: dup // 复制栈顶的元素此时栈顶有两个相同的异常对象引用 12: invokespecial #6 // 调用 Exception 类的构造函数初始化对象 15: athrow // 抛出栈顶的异常对象 16: astore_1 // 捕获异常并存入局部变量表的第1个位置 17: getstatic #2 // 获取 java/lang/System 类的 out 字段是 PrintStream 类型 20: ldc #7 // 将常量池中的 catch block 字符串压入栈顶 22: invokevirtual #4 // 调用 PrintStream 类的 println 方法输出字符串 25: jsr 26 // 无条件跳转到指令26finally块的起始位置 28: goto 34 // 执行完finally块后跳过 catch 块剩下的代码进入下一个处理流程 31: astore_2 // 捕获从finally块抛出的异常并存入局部变量表的第2个位置 32: jsr 26 // 无条件跳转到指令26finally块的起始位置 35: aload_2 // 从局部变量表的第2个位置加载异常对象至栈顶 36: athrow // 再次抛出该异常对象 37: astore_3 // 捕获异常并存入局部变量表的第3个位置 38: getstatic #2 // 获取 java/lang/System 类的 out 字段是 PrintStream 类型 41: ldc #8 // 将常量池中的 finally block 字符串压入栈顶 43: invokevirtual #4 // 调用 PrintStream 类的 println 方法输出字符串 46: ret 3 // 返回到 astore_3 指令之后的代码这段字节码中使用了 jsr 和 ret 指令这两个指令主要用于实现 finally 块的逻辑。jsr 指令会跳转到 finally 块的代码然后 ret 指令用于返回到 finally 块之前的代码继续执行。 字节码的解释 行0-15这部分对应 try 块的内容。在这个例子中它首先通过 getstatic 指令获取 System.out 对象然后通过 ldc 指令加载常量 “try block”最后调用 println 方法输出这个字符串。然后它创建一个 Exception 对象并抛出。 行16-25这部分对应 catch 块的内容。当 try 块抛出异常时执行流程会跳转到这部分。在这个例子中它首先通过 astore 指令将异常对象存储到局部变量表然后类似于 try 块的处理输出 “catch block” 字符串。 行37-46这部分对应 finally 块的内容。无论 try 块是否抛出异常这部分代码总是会被执行。在这个例子中它输出 “finally block” 字符串。 行25-32和行35-36这部分是对异常处理的一些额外控制。jsr 和 ret 指令用于实现无条件的跳转确保 finally 块总是会被执行。 8. 参考文档 张亚 《深入理解JVM字节码》https://www.jonesjalapat.com/2021/09/11/internal-working-of-java-virtual-machine/
http://www.hkea.cn/news/14569619/

相关文章:

  • 做网站 江门哪些网站做的不好
  • 青岛做网站皆赴青岛博坊网站建设
  • 怎么做导购网站什么 a wordpress
  • 手机商城网站建设做单页网站怎么选产品
  • 祝桥建设网站wordpress如何自建页面
  • 免费网站建设企业海南省旅游专业网站发展电子商务缺乏强大的专业产业资源做后盾
  • 2019做seo网站pageadmin建站系统破解版
  • 香河县建设局网站怎样增加网站的权重
  • 网站设置怎么删除网站在线咨询怎么做
  • 免费的制作手机网站平台东莞营销型网站建设找火速
  • 标准型网站构建网站建设预算申请如何写
  • 网站显示百度地图如何利用开源代码做网站
  • 微网站有什么用服务器租用收费标准
  • wordpress建站收录快wordpress 图片地址
  • 门户网站定义分类id wordpress
  • 网站开发 海淀wordpress圆角插件汉化
  • 建设本地端网站免费ui网站
  • 做网站哪个公司最好wordpress搜索文章内容
  • 深圳企业网站制作公司怎样电子商务很难就业吗
  • asp net网站开发语言的特点dw软件网站建设教程
  • 做a短视频网站网络优化师
  • 2017年网站建设公司青海网网站建设
  • 怎么让学生在网站上做问卷调查网站建设需要掌握什么知识
  • 怎样做网站怎要加服务器wordpress登陆后台
  • 做自己的网站如何赚钱的注册域名在哪里注册
  • 个人免费网站建站排名一个几个人做网站的几个故事电影
  • 天津网站建设方案报价网站开发的岗位及职责
  • 用asp做的网站有多少济南优化网页
  • 徐州建设公司网站网站建设 熊掌号
  • 注册免费的网站有吗ps怎么制作网页设计