在任何编程语言中,赋值操作都是最常见的操作之一,Java 自然也不例外。赋值时,使用赋值操作符=,它的意思是:“将等号右边的值(右值),复制给左边的值(左值)”。右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但左值必须是一个明确的、已命名的变量。也就是说,必须有一个物理空间可以存储等号右边的值。例如:

int a = 4;

就是将一个常数赋给一个变量。但是不能把任何东西赋给一个常数。

  对于基本数据类型来说,赋值是很简单的,因为基本数据类型(在堆栈中)存储了实际的数值,而并非指向一个对象的引用,所有在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方。但是在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作的时候,我们真正操作的是对象的引用,所以倘若“将一个对象赋值给另一个对象”,实际上是将“引用”从一个地方复制到另一个地方。这意味着如果对象在赋值的时候用b = c,那么对象bc都指向原本只有c指向的那个对象。通过下面的代码示例,我们将看到这个现象:

package com.hit.operator;

/**
* @Author Charies Gavin
* @Date 2017/8/26,下午1:38
* @GitHub https://github.com/guobinhit
*/
public class Book {
int price;
}

如上面的代码所示,我们建立了一个Book类,用来表示书籍,其仅有一个字段price,表示书籍的价格。

package com.hit.operator;

/**
* @Author Charies Gavin
* @Date 2017/8/26,下午1:38
* @GitHub https://github.com/guobinhit
*/
public class Assignment {
public static void main(String[] args) { // 创建两个实体对象
Book thinkingInJava = new Book();
Book headFirstPattern = new Book(); // 分别赋值
thinkingInJava.price = 108;
headFirstPattern.price = 68;
System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price); // 将 headFirstPattern (的引用)赋值给 thinkingInJava
thinkingInJava = headFirstPattern; System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price); // 修改 thinkingInJava 的价格(值),半价出售
thinkingInJava.price = 54; System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price);
}
}

如上面所示,我们建立了两个书籍对象thinkingInJavaheadFirstPattern,并分别对其价格进行赋值;然后,将对象headFirstPattern的引用赋值给thinkingInJava;接下来,调用thinkingInJava.price,修改其价格为半价。最后,运行程序,输出结果。显然,由于对象的赋值是操作的对象引用,因此在我们改变thinkingInJava的价格时,headFirstPattern的价格也随之改变。这种现象,我们称之为“别名现象”。

  当然,我们有时候并不希望发生别名现象,但如何避免呢?其实,想要避免别名现象也很简单,以上面的代码为例,我们只需要将对象赋值时的语句略作修改即可,如下所示:

package com.hit.operator;

/**
* @Author Charies Gavin
* @Date 2017/8/26,下午1:38
* @GitHub https://github.com/guobinhit
*/
public class Assignment2 {
public static void main(String[] args) { // 创建两个实体对象
Book thinkingInJava = new Book();
Book headFirstPattern = new Book(); // 分别赋值
thinkingInJava.price = 108;
headFirstPattern.price = 68;
System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price); // 将 headFirstPattern (的属性值)赋值给 thinkingInJava
thinkingInJava.price = headFirstPattern.price; System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price); // 修改 thinkingInJava 的价格(值),半价出售
thinkingInJava.price = 54; System.out.println("Thinking In Java : price is " + thinkingInJava.price);
System.out.println("Head First Pattern : price is " + headFirstPattern.price);
}
}

如上面所示,当我们将thinkingInJava = headFirstPattern修改为thinkingInJava.price = headFirstPattern.price之后,别名现象即可消除。


温馨提示:此内容源于《Java编程思想》,可以通过阅读《Java编程思想》了解更多的内容。

原博地址:https://blog.csdn.net/qq_35246620/article/details/77601547

转自CSDN-详述 Java 中的别名现象的更多相关文章

  1. 死锁线程探讨Java中的死锁现象

    题记:写这篇博客要主是加深自己对死锁线程的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 今天搞了一下Java的死锁机制,感到自己还是不怎么懂,所以就从一些简略的源代码中琢磨:我先 ...

  2. java中的死锁现象

    死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.由于线程被无限期地阻塞,因此程序不可能正常终止. java 死锁产生的四个必要条件: 1.互斥使用,即当资源被一个线 ...

  3. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  4. Java方法调用中的别名处理

    将一个对象传递到方法内部时,也会产生别名现象.//: PassObject.java// Passing objects to methods can be a bit tricky62class L ...

  5. Java中各类Cache机制实现解决方案[来自CSDN]

    摘要:在Java中,不同的类都有自己单独的Cache机制,实现的方法也可能有所不同,文章列举了Java中常见的各类Cache机制的实现方法,同时进行了综合的比较. 在Java中,不同的类都有自己单独的 ...

  6. 【Java学习笔记之十五】Java中的static关键字解析

    Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...

  7. java中引用对比C++指针

    前置知识地址:https://blog.csdn.net/wangfei8348/article/details/51383805 重点在后面的引用对比实验(测试出内存地址,我很开心哈哈哈,客观给个好 ...

  8. 什么是uuid以及uuid在java中的使用

    什么是UUID?UUID是Universally Unique Identifier的缩写,它是在一定的范围内(从特定的名字空间到全球)唯一的机器生成的标识符.UUID具有以下涵义: 经由一定的算法机 ...

  9. Java中堆内存和栈内存有什么区别

    本文链接:https://blog.csdn.net/wangbo1998/article/details/80379016Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基 ...

随机推荐

  1. win10搭建svn服务

    1,安装服务器版svnhttps://tortoisesvn.net/downloads.html查看版本 svn --version 2,创建版本仓库提倡创建公共仓库,那么可以多次增加项目svnad ...

  2. js点击加载更多可以增加几条数据的显示

      <div class="list"> <div class="one"> <div class="img" ...

  3. 使用Dockerfile定制ubuntu+nginx镜像

    实验目的:书写Dockerfile,定制ubuntu 14.04 + nginx 1.14.0的镜像. 实验过程: 1. 下载nginx-1.14.0  http://nginx.org/downlo ...

  4. java既然存在gc线程,为什么还存在内存泄漏?

    java既然存在gc线程,为什么还存在内存泄漏? 1.既然 Java 的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢?这个问题,我们需要知道 GC 在什么时候回收内存对象,什么样的内存 ...

  5. Windows编译安装使用cephfs客户端

    本文介绍如何将cephfs映射到windows的一个盘上,以磁盘映射的方式访问cephfs. 1.下载必要安装包 tdm-gcc:(安装时选32位)https://sourceforge.net/pr ...

  6. angular ,require.js, angular-async-loader实现单页面路由,控制器js文件分离

    https://github.com/heboliufengjie/appRoute/tree/re re 分支,实现,路由配置,控制器js文件分离

  7. 封装一个redis操作类来操作hash格式

    最近项目要用redis,依然是基于tp3.2. 发现thinkphp3.2自带的缓存类并不好使用,就自己封装了一个 目前只支持hash格式,其他数据类型的操作后面用到的时候再补充 <?php / ...

  8. 关于以base64编码形式上传图片

    第一次用,记录一下 HTML中的样式 HTML代码 1 <li class="orther" style="padding-top: 15px;"> ...

  9. React 的坑

    MemoryRouter 会缓存组件,导致有时候 componentDidMount 不会执行

  10. JS 删除数组中某个元素

    //删除红色的元素 splice(下标,长度) var arr = ['a','b','c','d']; arr.splice(1,1); console.log(arr);  //['a','c', ...