精华内容
下载资源
问答
  • 可变对象和不可变对象python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错)...

    python中的引用传递

    首先必须理解的是,python中一切的传递都是引用(地址),无论是赋值还是函数调用,不存在值传递。

    可变对象和不可变对象

    python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多线程读取的时候不需要加锁。

    不可变对象(变量指向的内存的中的值不能够被改变)

    当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。python中数值类型(int和float),字符串str,元组tuple都是不可变对象。

    下面以int类型为例简单介绍。

    a = 1

    print id(a) //40133000L,整数1放在了地址为40133000L的内存中,a变量指向这个地址。

    a += 1

    print id(a) //40132976L,整数int不可改变,开辟新空间存放加1后的int,a指向这个新空间。

    可变对象(变量指向的内存的中的值能够被改变)

    当更改该对象时,所指向的内存中的值直接改变,没有发生复制行为。python中列表list,字典dict,集合set都是可变对象。下面以list类型为例简单介绍。

    a = [1,2,3]

    print id(a) //44186120L。

    a += [4,5] //相当于调用了a.extend([4])

    print id(a) //44186120L,列表list可改变,直接改变指向的内存中的值,没开辟新空间。

    a = a + [7,8] //直接+和+=并不等价,使用+来操作list时,得到的是新的list,不指向原空间。

    print id(a) //44210632L

    引用传递后的改变

    a = [1,2,3]

    b = a

    b[0] = 2 //由于list是可变对象,改变b时候会导致a的改变,a和b都是[2,2,3]

    s = ‘abc‘

    s2 = s

    s2 += ‘d‘ //由于str是不可变对象,s2是新建的对象,s2的修改不会影响s。s为‘abc‘,s2为‘abcd‘。

    list注意点

    a = [1,2,3]

    b = a

    a is b //True,因为按引用传递,a和b存的地址(引用)是一样的,改变b相当于改变a。

    b = a[:]

    a is b //False,想使用list的值却不想修改原list时可以使用[:]拷贝一份到新空间。

    a =[ [0]*2 ]* 2 //以这种方式创建一个二维list,此时a为[[0,0],[0,0]]。

    a[0] == a[1] //True,这种创建方法的机制是复制list,所以2个list其实是同一个list。

    a[0][0] = 1 //改变第一个list时第二个list也改变,此时a为[[1,0],[1,0]]。

    a[0] += [1] //改变第一个list时第二个list也改变,此时a为[[1,0,1],[1,0,1]]。

    a[0] = [1,2] //a[0]指向创建的新list[1,2]。此时a[1]不变,a为[[1,2],[1,0,1]]。

    展开全文
  • [java] view plain copy/** * 验证final修饰的变量是引用不能变,还是引用的对象不能变 * StringBuilder 线程不安全 但速度快 * 引用初始化以后不能被改变 --- 不是指变量的值不可变,而是指向的变量...

    我们都知道final修饰变量时 会变为常量,但是使 用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

    下面让我们来看这段代码:

    [java] view plain copy
    1. /** 
    2.  * 验证final修饰的变量是引用不能变,还是引用的对象不能变 
    3.  * StringBuilder 线程不安全 但速度快 
    4.  * 引用初始化以后不能被改变 --- 不是指变量的值不可变,而是指向的变量地址不可变 
    5.  * @author Tomato 
    6.  * 
    7.  */  
    8. public class TestFinal {  
    9.     public static void main(String[] args) {  
    10.         final StringBuilder sb = new StringBuilder("haha");  
    11.         //同一对象的hashCode值相同  
    12.         System.out.println("sb中的内容是:"+sb);  
    13.         System.out.println(sb+"的哈希编码是:"+sb.hashCode());  
    14.         sb.append("我变了");  
    15.         System.out.println("sb中的内容是:"+sb);  
    16.         System.out.println(sb+"的哈希编码是:"+sb.hashCode());  
    17.           
    18.   
    19.         System.out.println("-----------------哈希值-------------------");  
    20.         TestFinal test = new TestFinal();  
    21.         System.out.println(test.hashCode());  
    22.         System.out.println(Integer.toHexString(test.hashCode()));  
    23.         System.out.println(test.getClass()+"@"+Integer.toHexString(test.hashCode()));  
    24.         System.out.println(test.getClass().getName()+"@"+Integer.toHexString(test.hashCode()));  
    25.         //在API中这么定义toString()等同于 getClass().getName() + '@' + Integer.toHexString(hashCode())  
    26.         //返回值是 a string representation of the object.  
    27.         System.out.println(test.toString());  
    28.     }  
    29. }  
    代码结果是:

    sb中的内容是:haha
    haha的哈希编码是:1928052572
    sb中的内容是:haha我变了
    haha我变了的哈希编码是:1928052572
    -----------------哈希值-------------------
    1398828021
    53606bf5
    class TestFinal@53606bf5
    TestFinal@53606bf5
    TestFinal@53606bf5

    可以看出StringBuilder中的内容变了 而所指向的哈希编码却没发生变化,在Java中每一个对象都有自己独一无二的哈希编码,根据这个编码就可以找到相关的对象,也就是说,根据这个编码你可以独一无二地确定这个对象。
    因而使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。


    总得来说对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

    展开全文
  • 使用final关键字修饰一个变量时,引用变量可以改变引用变量中所指的对象中的内容可以改变。 案例代码: public class Demo { public static void main(String[] args) { final StringBuffer a = ...

    使用final关键字修饰一个变量时,引用变量不可以改变,引用变量中所指的对象中的内容可以改变。


    案例代码:

    public class Demo {
        public static void main(String[] args) {
        	
    	    final StringBuffer a = new StringBuffer("luochenxi");
    	    
    //	    a = new StringBuffer(""); //报错
    	    a.append("_haha");
    	    
    	    System.out.println(a.toString());  //结果:luochenxi_haha
       }
    }


    展开全文
  • (2)不可变对象(变量指向的内存的中的值不能够被改变)当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。python中数值类型(int和float),布尔型bool,...

    (1)python中的引用传递

    • 首先必须理解的是,python中一切的传递都是引用(地址),无论是赋值还是函数调用,不存在值传递。

    (2)不可变对象(变量指向的内存的中的值不能够被改变)

    • 当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。python中数值类型(int和float),布尔型bool,字符串str,元组tuple都是不可变对象。

    a = 1print id(a)    # 40133000L,整数1放在了地址为40133000L的内存中,a变量指向这个地址。a += 1 print id(a)    # 40132976L,整数int不可改变,开辟新空间存放加1后的int,a指向这个新空间。

    (3)可变对象(变量指向的内存的中的值能够被改变)

    • 当更改该对象时,所指向的内存中的值直接改变,没有发生复制行为。python中列表list,字典dict,集合set都是可变对象。包括自定义的类对象也是可变对象。

    a = [1,2,3]print id(a)    # 44186120L。a += [4,5]     # 相当于调用了a.extend([4,5])print id(a)    # 44186120L,列表list可改变,直接改变指向的内存中的值,没开辟新空间。a = a + [7,8]  # 直接+和+=并不等价,使用+来操作list时,得到的是新的list,不指向原空间。print id(a)    # 44210632Ldef f(default_arg=[]):  default_arg.append('han')f() # ['han']f() # ['han', 'han'] # 函数默认的可变参数并不会每次重新初始化,而是使用上次的作为默认值。f([]) # ['han'] # 自行传入参数即可。def f(default_arg=None):  # 一个常见的做法是判断是否为空,为空则新建list,否则append    if default_arg is None:        default_arg = []    default_arg.append("some_string")    return default_arg

    (4)可变对象和不可变对象

    • python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多线程读取的时候不需要加锁。

    () is ()     # 返回True,因为tuple是不可变对象(不可改变,怎么定义都一样)'' is ''     # 返回True,因为str是不可变对象None is None # 返回True,None也是不可变的[] is []    # 返回False,因为是可变对象(可能改变,定义出来的两个必然要不一样){} is {}    # 返回False,因为是可变对象[] == []    # 返回True,注意==和is的不同,==只比较内容,is比较地址(id)class Student:  passStudent() is Student()  # 返回False,自定义类型也是可变对象,两次定义的对象地址是不同的id(Student()) == id(Student())  # 返回True,这里比较神奇,是因为创建一个Student对象,id()后返回地址但是进行了对象销毁,第二次又重新创建,两次占用了同一个地址

    (5)不可变对象的编译时驻留(类似java的常量池)

    学java的可以回忆回忆JVM的常量池

    int 的驻留:-5到256之间的整数都会进行驻留,再次定义的变量地址不变,为什么是-5到256呢,这是解释器决定的,依赖于具体实现。str的驻留:只包含字母,数字,下划线的字符串会驻留;长度为0或1的会驻留;

    a = -5    b = -5   a is b     # True,-5到256之间的整数,驻留(直觉上这部分数据会频繁调用,驻留可以节省资源)a = 256    b = 256   a is b     # True,-5到256之间的整数,驻留a = -6    b = -6   a is b     # False,非-5到256之间的整数,不驻留a = 257    b = 257   a is b     # False,非-5到256之间的整数,不驻留a = 'hello_world'    b = 'hello'+'_'+'world'a is b     # True,只包含字母,数字,下划线的字符串会驻留a = 'hello_world!'    b = 'hello_world!'a is b     # False,包含了特殊字符!, 不驻留'hello_world' is '_'.join(['hello', 'world'])     # False,因为驻留是编译阶段发生的,join在解释阶段才产生结果,未进行驻留a, b = 'hello_world!', 'hello_world!'a is b    # True 编译器的优化,在同一行赋值字符串时,只创建一个对象,指给两个引用。(ps:不适用3.7.x以下版本,3.7.x以下中会返回False,本焓主要用Python3.8.x)

    (6)关于驻留的陷阱

    • 跟驻留没有直接关系,是在命令行运行和py文件直接运行有一些差异。先看之前的小例子。

    a = 257    b = 257   a is b     # False,非-5到256之间的整数,不驻留。
    • 事实上,在命令行运行得到的才是False(我做的小实验一般都在交互式命令行上运行)如果把这三行放到py文件里,再直接运行,得到的是True,因为py文件是一次性编译的,而交互式命令行按一行为单位(严格说是命令结束时的全部,因为会有for while这种)编译或者在交互式中把这三行定义为函数,再调用函数,返回也是True。

    def func():    a = 257  b = 257  return a is bfunc()  # 返回True

    00bc9ef6c3236cace4010784b01729f4.png

    以上程序在命令行运行和py文件直接运行有一些差异。

    • 这是由python的代码块机制导致的,在同一代码块中相同值的赋值会指向同一个对象。函数体,类对象体,py文件,模块都可以看作一个代码块。

    • 在交互式命令行上,一行看作一个代码块(严格说是命令结束时的全部,因为会有for while这种),所以,这里所谓“代码块的优化”,就是前面提到的,同行赋值的优化,只在一行(代码块)上优化。

    • 到具体直接运行py文件,又有了更大范围的代码块的优化,所以连着两行相同赋值的对象,会指向同一个对象。

    420d2e86e7da1b755b3ce57850eb025b.png

    展开全文
  • (2)不可变对象(变量指向的内存的中的值不能够被改变)当更改该对象时,由于所指向的内存中的值不可改变,所以会把原来的值复制到新的空间,然后变量指向这个新的地址。python中数值类型(int和float),布尔型bool,...
  • 可变对象和不可变对象python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错)...
  • python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错),同时可以使得在多...
  • 可变对象和不可变对象python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错)...
  • 使用final关键字修饰一个变量时,是指引用变量能变,引用变量所指向的对象中的内容还是可以改变的。例如,对于如下语句:  final StringBuffer a=new StringBuffer("immutable");执行如下语句将报告...
  • 如果是引用数据类型变量,初始化之后指向另外一个对象。 基本数据类型: package cn.yqg.day2; public class StringTest { public static void main(String[] args) { final int ...
  • 可变对象和不可变对象python变量保存的是对象的引用,这个引用指向堆内存里的对象,在堆中分配的对象分为两类,一类是可变对象,一类是不可变对象。不可变对象的内容不可改变,保证了数据的不可修改(安全,防止出错)...
  • 常量引用即为对const的引用,其仅对引用可参与的操作做出了限定,但对于引用的对象是否为const常量并未做限定。若引用对象是const常量,那么无论通过何种方式都允许改变对象的值;若引用对象是非常量,则允许通过...
  •  此处说的“引用初始化以后不能被改变”不是指变量的值不可变,而是指向的变量地址不可变。这个得再去理解下引用的定义。   1.定义回顾  引用——引用就是某一变量(对象)的一个别名,对引用的操作与对变量...
  • 直接来举个例子说明一下这个问题:final StringBuilder sb=new StringBuilder("a");//下面这行代码会报错 ...由此可以说明,被final修饰之后,是引用变量的值不可变,而这个引用指向的对象是可以改变的。
  • 一、String类对象内容不可改变也就是说String类型字符串内容--旦声明赋值之后是不可以改变DEMO:观察代码发现了最后输出内容是“helloworld!”这与之前描述不同,其实这里改变不是原来字符串内容,...
  • 并且const对象一旦创建后其值不可改变,因此const对象必须初始化! 例子如下: const int i; //错误, const对象必须初始化 const int i = 512; //正确 i = 512; //错误,const对象一旦被创建就不可在被赋值 ...
  • 不可对象,该对象指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。 可变对象,该对象指向的...
  • 改变状态的意思是,改变对象内的成员变量,包括基本数据类型的值改变引用类型的变量能指向其他的对象,引用类型指向的对象的状态也改变。 区分对象和对象的引用 对于Java初学者, 对于String是...
  • 什么是可变/不可变对象不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。可变...
  • 什么是可变/不可变对象不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。可变...
  • 问:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后结果,那么这里到底是值传递还是引用传递? (下面内存图解:栈内存是先进后出,画错了 ) 答:是值传递。Java 编程语言...
  • 什么是可变/不可变对象不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。可变...
  • 一、String类对象内容不可改变 也就是说String类型字符串内容--旦声明赋值之后是不可以改变 DEMO:观察代码 发现了最后输出内容是“helloworld!”这与之前描述不同,其实这里改变不是原来字符串...
  • 什么是可变/不可变对象不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。可变...
  • 不可对象,该对象指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。 可变对象,该对象指向的...
  • 改变状态的意思是,改变对象内的成员变量,包括基本数据类型的值改变引用类型的变量能指向其他的对象,引用类型指向的对象的状态也改变。区分对象和对象的引用对于Java初学者, 对于Strin...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,432
精华内容 572
关键字:

引用指向的对象不可改变