详解JAVA 连等赋值问题
一、描述
关于 Java 连等赋值,例如a=b=c;
我们知道它是从右往左依次赋值的,其结果大致可以拆分为b=c;a=b
;,但是当栈中没有持有变量的引用时,则会出现问题,例如:
public class Node { int i; Node n; Node(int i) { this.i = i; } Node(Node n, int i) { this.i = i; this.n = n; } @Override public String toString() { return i + " "; } public static void main(String[] args) { Node nn = new Node(0); Node n1 = new Node(nn, 1); Node n2 = n1; n1.n = n1 = new Node(nn, 3); System.out.println(n1.toString() + n1.n.toString()); System.out.println(n2.toString() + n2.n.toString()); } } // 打印: // n1:3 0 // n2:1 3
如果将以上n1.n = n1 = new Node(nn, 3);
拆分后:
n1 = new Node(nn, 3); n1.n = n1; // 打印: // n1:3 3 // n2:1 0
二、分析
1. 初始情况
2. 拆分的赋值
- 首先
n1
指向node3
; - 然后
n1.n
指向node3
自身,形成闭环 - 所以结果打印
n1:3 3 ;n2:1 0
,这里很容易理解
3. 连等赋值
在开始赋值的时候因为 stack 里面并没有持有n1.n
的引用,所以会现在 stack 中创建一个临时变量指向n1.n
,如图:
所以在连等赋值之后变为:
所以最终n1.n = n1 = new Node(nn, 3);
会打印n1:3 0;n2:1 3
;
- 因为在执行完
n1 = new Node(nn, 3);
之后,stack 中的n1.n
仍然指向原n1
中的node
; - 在执行
n1.n = n1
的时候,两个n1
所指示的对象已经不再相同,所以会等到以上结果;
三、总结
对于以上问题之所以会出乎意料,就是因为原本以为是原子性的步骤,实际上是分布完成的;
类似的问题其实在Virtual Machine Specifications中一定是能找到更为准确的答案的,如果你有兴趣可以自行查阅;
以上所述是小编给大家介绍的JAVA 连等赋值问题详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
相关推荐
-
浅谈java中String的两种赋值方式的区别
类似普通对象,通过new创建字符串对象.String str = new String("Hello"); 内存图如下图所示,系统会先创建一个匿名对象"Hello"存入堆内存(我们暂且叫它A),然后new关键字会在堆内存中又开辟一块新的空间,然后把"Hello"存进去,并且把地址返回给栈内存中的str, 此时A对象成为了一个垃圾对象,因为它没有被任何栈中的变量指向,会被GC自动回收. 直接赋值.如String str = "Hello&
-
浅谈Java变量赋值运算符及相关实例 原创
Java程序中,需要进行大量的计算,所以要使用到运算符号,下面来给大家说明Java赋值运算符如何运用. 赋值运算符以符号"="表示,它是一个二元运算符(对两个操作数作处理),其功能是将右方操作数所含的值赋给左方操作数.例如: int a = 100; 该表达式是将100赋值给变量 a .左方的操作数必须是一个变量 ,而右边的才做书则可以是任何表达式,包括变量(如 a .number).常量(123.'book').有效表达式(如55*66). 1:使用赋值运算符为变量赋
-
Java中类赋值的解释实例详解
Java中类赋值的解释实例详解 Java是面向对象的存储语言,进行的是信息的传递,也就是类的赋值,实际上他们占用的是同样的存储空间: 下面上一个自己写的例子: 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
-
详解JAVA 连等赋值问题
一.描述 关于 Java 连等赋值,例如a=b=c;我们知道它是从右往左依次赋值的,其结果大致可以拆分为b=c;a=b;,但是当栈中没有持有变量的引用时,则会出现问题,例如: public class Node { int i; Node n; Node(int i) { this.i = i; } Node(Node n, int i) { this.i = i; this.n = n; } @Override public String toString() { return i + " &
-
详解Java线程池和Executor原理的分析
详解Java线程池和Executor原理的分析 线程池作用与基本知识 在开始之前,我们先来讨论下"线程池"这个概念."线程池",顾名思义就是一个线程缓存.它是一个或者多个线程的集合,用户可以把需要执行的任务简单地扔给线程池,而不用过多的纠结与执行的细节.那么线程池有哪些作用?或者说与直接用Thread相比,有什么优势?我简单总结了以下几点: 减小线程创建和销毁带来的消耗 对于Java Thread的实现,我在前面的一篇blog中进行了分析.Java Thread与内
-
详解java的值传递、地址传递、引用传递
详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前的理解,java中基本数据类型是值传递,对象是地址(引用)传递.给大家看个例子: public class ObjectTrans { public static void main(String[] args) { String name = "123"; SChange(name);
-
详解Java的堆内存与栈内存的存储机制
堆与内存优化 今天测了一个项目的数据自动整理功能,对数据库中几万条记录及图片进行整理操作,运行接近到最后,爆出了java.lang.outOfMemoryError,java heap space方面的错误,以前写程序很少遇到这种内存上的错误,因为java有垃圾回收器机制,就一直没太关注.今天上网找了点资料,在此基础上做了个整理. 一.堆和栈 堆-用new建立,垃圾回收器负责回收 1.程序开始运行时,JVM从OS获取一些内存,部分是堆内存.堆内存通常在存储地址的底层,向上排列. 2.堆
-
详解java中接口与抽象类的区别
详解java中接口与抽象类的区别 1.abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系.但是,一个类却可以实现多个interface. 2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的. 3.abstract c
-
详解java中的四种代码块
在java中用{}括起来的称为代码块,代码块可分为以下四种: 一.简介 1.普通代码块: 类中方法的方法体 2.构造代码块: 构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行. 3.静态代码块: 用static{}包裹起来的代码片段,只会执行一次.静态代码块优先于构造块执行. 4.同步代码块: 使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性.同步代码块需要写在方法中. 二.静态代码块和构造
-
详解Java面试官最爱问的volatile关键字
本文向大家分享的主要内容是Java面试中一个常见的知识点:volatile关键字.本文详细介绍了volatile关键字的方方面面,希望大家在阅读过本文之后,能完美解决volatile关键字的相关问题. 在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识. 下面我们以一次假想的面试过
-
详解java面试题中的i++和++i
代码如下所示: public class TestPlusPlus{ public static void main(String[] args){ int k = addAfterReturn(10); System.out.println(k); //输出 10 int k1 = addbeforeReturn(10); System.out.println(k1); //输出11 } public static int addbeforeReturn(int i){ return ++i;
-
详解Java中AbstractMap抽象类
jdk1.8.0_144 下载地址:http://www.jb51.net/softs/551512.html AbstractMap抽象类实现了一些简单且通用的方法,本身并不难.但在这个抽象类中有两个方法非常值得关注,keySet和values方法源码的实现可以说是教科书式的典范. 抽象类通常作为一种骨架实现,为各自子类实现公共的方法.上一篇我们讲解了Map接口,此篇对AbstractMap抽象类进行剖析研究. Java中Map类型的数据结构有相当多,AbstractMap作为它们的骨架实现实
-
详解Java 10 var关键字和示例教程
关键要点 Java 10引入了一个闪亮的新功能:局部变量类型推断.对于局部变量,现在可以使用特殊的保留类型名称"var"代替实际类型. 提供这个特性是为了增强Java语言,并将类型推断扩展到局部变量的声明上.这样可以减少板代码,同时仍然保留Java的编译时类型检查. 由于编译器需要通过检查赋值等式右侧(RHS)来推断var的实际类型,因此在某些情况下,这个特性具有局限性,例如在初始化Array和Stream的时候. 如何使用新的"var"来减少样板代码. 在本文中,
随机推荐
- IOS使用NSUserDefault去实现界面传值和数据存储
- ASP.NET 应用程序级 验证用户是否登录 一般处理程序
- asp.net String.format中大括号的加入方法
- asp.net 数据类型转换类代码
- 加速XP搜索功能堪比vista
- ThinkPHP惯例配置文件详解
- PHP 绘制网站登录首页图片验证码
- PHP写的求多项式导数的函数代码
- python中self原理实例分析
- python with statement 进行文件操作指南
- 详解hibernate自动创建表的配置
- Mysql创建通用设备管理信息系统数据库
- 一步一步教你网站同步镜像(转载)
- Android 点击屏幕空白处收起输入法软键盘(手动打开)
- 木翼下载系统中说明的PHP安全配置方法
- 学习php设计模式 php实现模板方法模式
- Vue.js第二天学习笔记(vue-router)
- SQL中distinct的用法(四种示例分析)
- js 弹出新页面避免被浏览器、ad拦截的一种新方法
- JS完成代码前最好对其做5件事