`

赋值、引用

    博客分类:
  • Java
 
阅读更多
此内容摘自《Thinking in java》Page39.

赋值使用操作符“=”。它的意思是“取右边的值(即右值),把它复制给左边(即左值)”。右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但是左值必须是一个明确的、已命名的变量。也就是说,必须有一个物理空间可以存储等号右边的值。举例来说,可将一个常数赋给一个变量:
a = 4;
但是不能把任何东西赋给一个常数,常数不能作为左值(比如不能4=a;)。

对基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方。例如,对基本数据类型使用a=b,那么b的内容就赋值给a。若接着又修改了a,而b根本不会受这种修改的影响。作为程序员,这正是大多数情况下我们希望看到的。

但是在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对对象的引用。所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方复制到另一个地方。这意味着假若对对象使用c=d,那么c和d都指向原本只有d指向的那个对象(如果c此前包含的对对象的引用是指向另一个对象,那么在执行c=d赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象将被“垃圾回收器”自动清理(注意条件:不可达时才会被清理))。由于赋值操作的是一个对象的引用,所以此时修改c的时候也就相当于修改了d!这是由于c和d包含的是相同的引用,它们指向相同的对象。
这种特殊的现象通常被称作“别名现象”,是java操作对象的一种基本方式。

方法调用中的别名问题
将一个对象传递给方法时,也会产生别名问题:
class Letter{
    char c;
}
public class PassObject{
    static void f(Letter y){
        y.c = 'z';
    }
    public static void main(String[] args){
        Letter x = new Letter();
        x.c = 'a';
        print(x.c); //打印a
        f(x);
        print(x.c); //打印z
    }
}

在许多的编程语言中,方法f()似乎要在它的作用域内复制其参数Letter y的一个副本;但实际上只是传递了一个引用。所以代码行y.c = 'z';实际改变的是f()之外的对象。

------------------------------------------------------------

堆栈:对象的引用、基本类型的变量(这个变量直接存储值),存储在堆栈中。堆栈位于通用RAM(随机存取存储器)中。
:一种通用的内存池,也位于RAM中,用于存放所有的java对象。
常量存储:常量值通常直接存放在程序代码内部,这种存储区的一个例子是字符串池。所有的字面常量字符串和具有字符串值的常量表达式都自动是内存限定的,并且会置于特殊的静态存储区中,比如ROM(只读存储器)。

------------------------------------------------------------

java中的引用与javascript中的引用是一样的,都分为基本类型数据与引用类型数据:
基本类型数据
    例如:obj = 3;
         ref = obj;
    此时,是拷贝一份obj的值给ref,拷贝完成后,ref与obj之间就没有任何关系了。
引用类型数据:javascript引用与java引用一样,都是指向最终的对象(位于堆区),而非指向引用本身(堆栈区)
   例如obj是一个对象: obj = new Obj(); //在js中,obj = {a:1,b:2}
          ref = obj;
    此时,ref与obj所指向的对象是同一个,改变它们俩中的任意一个,另一个也会跟着改变;
如果obj再指向其他对象,这时就跟ref没有关系了,ref还指向开始的那个对象(类似的,如果ref指向其它对象,那么ref跟obj就没有关系了,它们分别指向不同的对象了);下面是一个js中引用的例子:
var obj = {}; // 空对象 
var ref = obj; // 引用

obj.name = "objectA" ;   
alert(ref.name); //ref跟着添加了name属性  打印objectA

obj = ["one", "two", "three"]; //obj指向了另一个对象(数组对象)
alert(ref.name); //ref还指向原来的对象 打印objectA
alert(obj.length ); //打印3
alert(ref.length); //打印undefined
obj只是对一个匿名对象的引用,所以,ref并非指向它,当obj指向另一个数组对象时,可以看到,引用ref并未改变,而始终指向这那个后来添加了name属性的"空"对象"{}"

同一个方法中
ref = obj
基本类型数据:  拷贝一份给ref
引用类型数据:  ref 与 obj指向同一个对象,改变她们俩个的任意一个,另一个也会跟着改变; 如果其中一个又指向了其它对象时,那么跟另一个就没有关系了,另一个还指向原来的那个对象。

当做参数传递到另一个方法中
传值---传递基本数据类型参数
引用传递---对象作为参数
1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。 例如,int,float,Integer,String等
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。
分享到:
评论

相关推荐

    C#引用类型的赋值 类的赋值

    ### C#中引用类型的赋值详解 在C#编程语言中,变量分为两种类型:值类型和引用类型。本文将重点介绍引用类型的赋值特点及其背后的实现机制。 #### 一、引用类型的定义与特点 在C#中,除了基本类型(如`int`、`...

    浅谈Java中的克隆close()和赋值引用的区别

    在Java编程中,克隆(Cloning)和赋值引用是两种不同的对象复制方式,它们在处理对象状态和内存管理时有着显著的区别。本文将详细探讨这两种方式,并通过示例代码来阐述它们的工作原理。 首先,让我们理解克隆的...

    python dict 字典 以及 赋值 引用的一些实例(详解)

    下面将详细讲解字典的创建、赋值以及引用的相关知识。 1. **字典创建**: - 方法1:通过键值对的直接初始化,如`dict = {'name': 'earth', 'port': 80}`。 - 方法2:通过元组的列表构建字典,如`fdict = dict((['...

    值类型与引用类型(.html)

    当传递或赋值引用类型时,只复制引用,而不是整个对象。 - 特性: - 存储在堆中,访问速度相对较慢,但可以动态分配内存。 - 赋值或传递时,复制的是引用,而非对象,因此改变引用副本不会影响原始对象。 - 可以...

    Java是传值还是传址引用

    这意味着可以在方法内部修改对象的状态而不影响原始对象的引用,但如果重新赋值引用,则不会影响原始对象。 - 引用是一种数据类型,用于存储对象在内存中的地址。不同的引用可以指向同一个对象,但每个引用本身都是...

    对象与引用之间的一些基本概念

    4. **赋值引用**:使用`=`操作符将引用变量`veh1`指向新创建的`Vehicle`对象。 在这个过程中,对象本身是不可见的,我们只能通过引用变量来访问和操作对象。引用变量就像是连接对象的“绳子”,我们可以通过改变...

    php 传值赋值与引用赋值的区别

    传值赋值:当将一个表达式的值赋予一个... 引用赋值:新的变量简单的引用了原始变量,改变新的变量将影响到原始变量使用引用赋值,简单地将一个&符号加到将要赋值的变量前(源变量) 类型戏法PHP 在变量定义中不需要

    编译原理实验报告

    本实验报告针对的是编译原理课程中的两项核心实践内容:词法分析器的设计以及赋值语句的翻译程序设计。实验旨在帮助学生深入理解编译原理的基础概念和技术实现细节。 #### 二、词法分析程序设计实验知识点 ##### 1...

    赋值语句语法分析

    - **变量初始化**:变量在引用前需初始化,未初始化的变量默认值根据其类型决定(如整型默认为0,字符型默认为空格)。 #### 二、赋值语句的表示 - **中缀表示**:传统表示方法,运算符位于两个操作数之间。例如:...

    winform 值类型引用类型赋值源码

    本文将深入探讨“值类型”与“引用类型”在WinForm中的赋值机制,通过源码分析来理解这两者的差异。 首先,我们要明白值类型与引用类型的基本概念: 1. 值类型:值类型包括基本数据类型(如int、double、bool)...

    传值赋值与引用赋值的区别[参考].pdf

    在软件开发过程中,尤其是使用PHP这种动态类型的编程语言时,理解传值赋值与引用赋值的区别至关重要。这两种赋值方式决定了变量之间的关联性以及值的传递方式。 **传值赋值** 是指将一个变量的当前值完整地复制给另...

    C++智能指针实现(包含拷贝构造,赋值函数,引用解引用重载)

    本主题将深入探讨如何实现一个简单的智能指针,包括拷贝构造函数、赋值运算符以及引用和解引用操作符的重载。我们将使用C++标准库中的`std::shared_ptr`作为参考,并在Visual Studio 2019环境下进行编译。 首先,...

    父类赋值给子类

    在编程领域,特别是面向对象编程中,"父类赋值给子类" 是一个常见的操作。C# 作为一种强大的面向对象的语言,提供了多种方式来实现这种继承关系下的数据复制。这里我们将深入探讨如何在 C# 中进行父类属性到子类属性...

    .net core 面试题目汇总

    值类型的赋值会产生一个新的数据副本,而引用类型是直接赋值引用。值类型分配在栈上,而引用类型分配在堆上。值类型变量占用内存由系统分配和释放,而引用类型则由程序申请分配,释放由 GC 系统垃圾清理回收。比较值...

    java 子类对象赋值给父类对象的使用

    当我们创建一个子类对象并将其赋值给父类引用时,这种行为被称为向上转型(Upcasting)。这一过程是自动且安全的,因为子类对象包含了父类的所有属性和方法。下面我们将深入探讨这个主题,包括它的原理、示例代码...

    delphi事件赋值操作

    为防止内存泄露,确保在不再需要事件处理程序时取消对其的引用。 9. **事件的安全性**: 在多线程环境中,事件处理需考虑线程同步问题,以防止并发访问同一事件导致的问题。 10. **自定义事件类型**: 除了标准...

    operator=赋值检测学习

    - **返回引用**:赋值运算符通常返回左操作数的引用,以便链式赋值,如`a = b = c = d;` 4. **拷贝构造函数与赋值运算符**: 当创建一个新对象并用已存在的对象初始化时,会调用拷贝构造函数。而当一个对象被赋值...

    vuex直接赋值的三种方法总结

    这样在模板中我们就可以直接通过{{ num }}来引用这个状态,而无需每次都通过$store来访问。 第二种方法是利用Vuex提供的辅助函数mapState来简化对状态的访问。mapState可以生成计算属性,帮助我们将Vuex的状态映射...

    赋值传值,引用传值,指针传值的区别

    构造函数,借助构造函数 解释 【赋值传值】,【引用传值】,【指针传值】

Global site tag (gtag.js) - Google Analytics