Java左值和右值的思考

本文最后更新于:2021年12月4日 下午

Java左值和右值的思考

前言

昨天做了一道LeetCode,用到小根堆「PriorityQueue」,其中一个操作让我困惑了很久。

  • 小根堆存储的是原数组为负值的下标,则小根堆堆顶为最小负数的下标
  • 本意是循环中,每次让最小负数取到相反数,变成一个正数
  • while (k-- > 0) nums[queue.peek()] = -nums[queue.poll()];
    • 这一操作让我疑惑了很久,根据赋值表达式的性质,应该是从右计算到左,但是如果这样思考的话,就会让 poll 先进行,后面才 peek ,这样下标的计算就出错了。

断点分析

  1. 先直接测试 num[q.peek()] = -num[q.poll()] 这一写法

num[q.peek()] = -num[q.poll()]

num[q.peek()] = -num[q.poll()]

  • 即成功将 num 的第一个元素变成相反数
  1. q.peek() 抽取变量

将q.peek()抽取变量

将q.peek()抽取变量

  • 按照预期「将 peek 的下标元素置为相反数」,提取变量,即下标,这种写法清晰明了
  1. q.poll() 抽取变量

将q.poll()抽取变量

q.poll() 让堆顶出队,保存下来,但这改变堆结构,在下次 peek 就不再是原堆的最小值元素

将q.poll()抽取变量

  • 最终影响到第二个元素,而不是第一个元素,不符合预期。

字节码分析

反编译 .class 文件,分析执行过程

  1. num[q.peek()] = -num[q.poll()]

num[q.peek()] = -num[q.poll()]

  • 显然是先执行的 peek 后执行 poll,符合预期
  1. q.peek() 抽取变量

将q.peek()抽取变量

  • 也是按照预期执行 peek 后执行 poll
  1. q.poll() 抽取变量

将q.poll()抽取变量

  • 先执行的 poll 后执行 peek,不符合预期

Summary

  • 不能按照赋值表达式 = 从右向左运行的思想思考 nums[queue.peek()] = -nums[queue.poll()];
  • 最终的赋值的确会按照右向左执行「赋值操作」,完成 置相反数 的操作
  • 但是从最终字节码的执行顺序来看,📌猜测:对于表达式的计算,会从左向右计算,将前序准备工作「取值」完成后,才进行写操作,赋值。

🔗Reference

1005. K 次取反后最大化的数组和


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!