关于我对 [ 一段很有意思的代码 ] 一文有些疑问这件事

2022-05-26 15:18:17 浏览数 (1)

关我疑事

  • 前言
  • 一、原文简介
  • 二、分析
    • 1.改造代码, 增加信息打印
    • 2.分析
    • 3. 总结
  • 三、体会

前言

闲暇之余, 抱着学习(好奇)的心态去看了这样一篇文章 一段很有意思的代码!! 这是由我最尊敬(指每次遇到比较系统的问题都会去这里学习, 一日为师下句我就不说了~)的公众号 [ 菜鸟教程 ] 转载的 业内分布式技术大佬 [ 冰河 ] 原创的一篇文章. 原文找了半天没看到, 不清楚这个疑问是否有人已经提出. 因此我就斗胆的提出我的拙见~ 如有问题欢迎大家指出. 鄙人在此抱拳~~~


一、原文简介

本文对以下代码在调用 print 方法后, 同时执行了ifelse分支进行分析, 代码和输出结果如下图所示:

代码语言:javascript复制
public class Test {

    public static void main(String[] args) {
    	// 核心代码
        new Test().print(args==null || new Test() {{Test.main(null);}}.equals(null));
    }

    public void print(boolean flag){
        if(flag){
            System.out.println("我是if语句的分支");
        }else{
            System.out.println("我是else语句的分支");
        }
    }
}

原作者文中说法可简述为,:

在 || 前 args == null 为 true,执行 print() 方法的 if 语句.

后面因为再次创建了一个 Test 类的对象实例(不为null), 因此 equals((Object)null) 为 false , 执行 print() 方法 else语句

通过留言来看, 大多说人都把作者的描述理解为 || 前面为 true 后, 又继续执行后面的

那么事实真是如此吗?, 看到这里, 我眉头一皱发现事情并不简单

其实, 仔细阅读后你就会发现, 作者的本意不是如此. 因为文中强调 main 方法执行了两次

因此, 综合来看, 作者的意思实际是: 第一次执行 main 时, args == null 为 true , 执行 print() 方法的 if 语句,

然后第二次执行main 时, equals((Object)null) 会返回 false, 执行了 else 语句的逻辑

二、分析

那么? 事情真的如作者说的那样? 出于一种奇怪的本能我发现事情并没有这么简单 于是, 带着疑问我们来对代码动点小手术, 加两行打印语句, 看下执行结果

1.改造代码, 增加信息打印

代码语言:javascript复制
    public static void main(String[] args) {
    	// 判断 args == null 的结果情况
        System.out.println(args == null);
        new Test().print(args==null || new Test() {
            {
                System.out.println("第二层main()执行开始" );
                Test.main(null);
                System.out.println("第二层main()执行结束" );
            }
        }.equals(null));
    }
    public void print(boolean flag){
        if(flag){
            System.out.println("我是if语句的分支");
        }else{
            System.out.println("我是else语句的分支");
        }
    }

代码运行结果

2.分析

  1. 可以看到, 第一次运行时, main函数入参 args == null 是false !
  2. 为什么 为false ? 这就考察我们 == 的含义这个知识点了 在基本数据类型时 == 比较的是值, 而在对象或其他类型中比较的是引用地址 因为在函数声明时已经定义好 args 数组并在堆内存中开辟空间建立历引用(相当于初始化), 因此 args == null结果为false
  3. 我们在把核心代码 new Test().print(args==null || new Test() {{Test.main(null);}}.equals(null)); 优化成 new Test().print(A || B); , 所以在第一次执行外层main方法时, A = args == null = false, 由于 || 代表短路或, 只有 || 前后都为false 才返回 false, 而如果 || 前为 false 为 false 时会继续判断后面的语句 在本代码中相当于继续执行B代码块
  4. 执行B代码块后, 相当于在main方法中再次调用了一次 main 方法 在第二次 main 中通过类名.静态方法来调用main方法, 并且传参null. 这相当于强制令数组等于null, 因此在执行第二次main方法中, new Test().print(A || B); A代码块为true, 因为 || 代表短路或, 遇到true会直接返回, 所以会直接执行print方法的if语句
  5. 执行玩第二次main方法后, 第一次 main 方法也执行完毕, 由下图图可知 B 永远为 false 因此在第一次main方法的核心代码 new Test().print(A || B)中 false || false 结果为 false , 所以才会执行else 语句!

3. 总结

第一次运行main 方法时, 核心代码 new Test().print(A || B); 因为 A 代码块为 false 因此执行 B 代码块 但在B代码块中又调用了一次main方法并且为main方法设置入参, 导致没有执行完第一次main 方法的 B代码块前又执行第二次main 方法, 它的核心代码也是 new Test().print(A || B);, 并且 A为true, 因为短路或遇到 true 会直接返回 true, 因此首先执行 print 方法的 if 语句 然后将第一次 main 方法的 B 代码块执行完毕(false), 同时因为 A = false, A || B 为 false, 因此执行 print 方法的 else 语句


三、体会

  1. 通过对一个问题的探究巩固了很多知识点 比如: 短路或的使用, == 的含义, 函数以及形参在内存中的模型等等
  2. 对于感到兴趣或者疑问的问题, 不妨多动手试试, 或许有意想不到的结果
  3. 夏天到了, 一曲 冰柜 送上

0 人点赞