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

十个常见的网络推广渠道营销排名seo

十个常见的网络推广渠道,营销排名seo,株洲市哪里有做公司官方网站,企业网站免费文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用,聊一下我们常见的一些java语句的特性底层…

文章目录

  • 前言
  • 1. if语句
    • 字节码的解析
  • 2. for循环
    • 字节码的解析
  • 3. while循环
  • 4. switch语句
  • 5. try-catch语句
  • 6. i++ 和++i的字节码
  • 7. try-catch-finally
  • 8. 参考文档

前言

上一章我们聊了《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个位置的元素(10)24: 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 增加1

++i 的伪字节码:

iinc 1 by 1             // 将局部变量表中的变量 i 增加1
iload_1                 // 从局部变量表中加载变量 i 到操作数栈顶

可以看到,i++++i 的主要区别在于加载和增加操作的顺序不同。i++ 是先将 i 加载到操作数栈顶,然后再增加 i 的值;而 ++i 是先增加 i 的值,然后再将 i 加载到操作数栈顶。这就解释了 i++++i 在语义上的不同:i++ 是先取值后加1,++i 是先加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   // 无条件跳转到指令26(finally块的起始位置)
28: goto          34   // 执行完finally块后,跳过 catch 块剩下的代码,进入下一个处理流程
31: astore_2       // 捕获从finally块抛出的异常并存入局部变量表的第2个位置
32: jsr           26   // 无条件跳转到指令26(finally块的起始位置)
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 指令之后的代码

这段字节码中使用了 jsrret 指令,这两个指令主要用于实现 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. 参考文档

  1. 张亚 《深入理解JVM字节码》
  2. https://www.jonesjalapat.com/2021/09/11/internal-working-of-java-virtual-machine/
http://www.hengruixuexiao.com/news/13805.html

相关文章:

  • wordpress首页悬浮框seo建设招商
  • 镇江网站建设联系思创今日国际新闻摘抄十条
  • 页面设计的对称方法包括哪几种形式天津seo关键词排名优化
  • 郑州做网站推内容营销案例
  • 昆明电商网站建设百度推广一年大概多少钱
  • 商城网站建设实例需求腾讯广告平台
  • 桂阳网站设计深圳公关公司
  • 自己做的网站在浏览器上显示不安全中国北京出啥大事了
  • 微信2023新版下载seo网站排名优化教程
  • 个人网站备案怎么写厦门seo管理
  • wordpress roleseo 优化技术难度大吗
  • 网站数据库管理系统2023b站推广大全
  • 网站秒杀怎么做十大小说网站排名
  • 高网站建设山东网络优化公司排名
  • 阿里云建网站步骤网络营销学院
  • 网站为什么做等保如何让百度搜索到自己的网站
  • 做网站建设费用预算移动网站优化排名
  • seo怎么做最佳广州网站营销优化qq
  • 厦门做网站多个人网页生成器
  • 杭州网站建设设计公司百度地图导航网页版
  • 国税政务公开网站建设什么平台免费推广效果最好
  • 中国建设官方网站登录旅游网站的网页设计
  • 温州做网站什么是口碑营销
  • wordpress 浮动div南京市网站seo整站优化
  • wordpress 搭建wikiseo课程培训课程
  • 怎么样申请网站域名国际新闻 军事
  • 网站备案必须在公司注册地seo教程最新
  • 内网网站建设方面政策云南最新消息
  • 哪个网站做任务赚钱多百度旧版本下载
  • 网易企业邮箱怎么样优化方案官网电子版