찾다

 >  Q&A  >  본문

c# - 关于java中Int等类型装箱时发生的奇怪现象

各位朋友,我下面说一下我的理解,各位看看是否正确
(注意不要瞎延伸,如果我对就告诉我说得是对的,让我得到确认无误。另外如果我错了不要鄙视我,帮忙提出错在哪并给出真正的答案是个好方法。
我在知乎问问题有人把我鄙视的心理拔凉拔凉的了都):

理解1:
int,byte,short这几个基本类型变量的装箱操作,底层都有一个缓冲池(java源码可以找到实现),也就是Object a=200; 这样的操作,就会创建一个新对象装下200,因为200超出了缓冲池。所以每次装箱都new新的对象来包装200.因此:
Object a=200;与Object b=200; 判断a==b返回false,因为其a和b不是指向同一个对象。
而Object a =100与Object b=100 其a和b是指向同一个对象。(因为由于缓存池机制,导致装箱的时候,只从池子中取一个值为100的对象返回,所以a和b地址相同,a==b返回true)

理解2:
同时,装箱的int,byte,short有个不可变的特性(就像String类的对象也具有不可变的性质)。因此每次改变某个对象的值,都是去创建一个新的对象,而无法真正改变缓存池中这个对象本身。例如:
Object a=200;
Object b=a; //现在a==b返回true
b=201; //想修改b指向的对象的值,但由于装箱后的int,short以及String之类的那种不可变性,导致201是创建了一个新对象,把地址返回给b。而不是把原来那个200对象改为201.

重复:在第二行,a和b是指向同一个对象,但是第三行修改b对象的时候,由于b对象的不可修改特性,导致最后结果是b是指向一个201的新对象,a还是指向200的那个对象。 也就是说装箱后的基本类型不能再次被改变,只能创建新对象。(你有改变那个200对象本身的办法吗)

理解3:
以上的缓冲池和不可变性适用于String对象。(虽然String没有装箱,但是String的机制跟装箱后的Integger差不多一样)

理解4:
装修后的int,short,byte。以及String类,都有一个办法直接去创建新的对象,而不经过缓存池。那就是new。
例如String a="123"; String b="123"; 这样a和b都指向缓存池中的"123"
而String a=new String("123"); 与 String b=new String("123");
就不经过缓存池,直接创建了2个"123"的对象所以,a==b返回false。

ringa_leeringa_lee2788일 전481

모든 응답(3)나는 대답할 것이다

  • 大家讲道理

    大家讲道理2017-04-17 12:59:30

    String是对象,没有包装器。

    String a = "123";直接把引用指向常量池。而String b = new String(a);是把a的内容在堆中复制一份。

    회신하다
    0
  • PHPz

    PHPz2017-04-17 12:59:30

    String 还要考虑编译器优化的情况

            String a = "xy";
            String b = "x" + "y";
            assertSame("case 1", a, b); //true 编译器优化
            String c = getString("x", "y");
            assertSame("case 2", a, c); //false 
    
        private String getString(String x, String y) {
            return x+y;
        }
    
    

    회신하다
    0
  • ringa_lee

    ringa_lee2017-04-17 12:59:30

    之前没仔细想过,看了楼主的写的理解,自己基本跟楼主理解的是一样的。
    不过感觉理解2的例子没举好,200已经超过了缓冲池,就算把第三行的b=201;改成b=200;也是会新建对象的,a==b也会返回false。

    회신하다
    0
  • 취소회신하다