一个java引用类型的问题

问题如下,代码在下面:
调用函数前a的值为:18
a的内存地址为:1013423070
a属性的内存地址为:380936215
b的内存地址为:1013423070
b属性的内存地址为:142638629
调用函数后a的值为:0


为什么a属性的内存地址和b属性的内存地址不一样呢?这里不是只有一个Person对象么?
a属性的内存地址为:380936215
b属性的内存地址为:142638629


又有一个问题,a和b是不同的两个变量,为什么这里内存地址会相同呢?应该是a和b的值相同吧?
a的内存地址为:1013423070
b的内存地址为:1013423070


public class TestZhiAndYinYong
{
    //引用类型:类和对象
    public static void main(String[] args)
    {
        Person a = new Person();
        a.age = 18;
        System.out.println("调用函数前a的值为:" + a.age);
        System.out.println("a的内存地址为:" + System.identityHashCode(a));
        System.out.println("a属性的内存地址为:" + System.identityHashCode(a.age));
        fun(a);
        System.out.println("调用函数后a的值为:" + a.age);
    }

    public static void fun(Person b)
    {
        b.age = 0;
        System.out.println("b的内存地址为:" + System.identityHashCode(b));
        System.out.println("b属性的内存地址为:" + System.identityHashCode(b.age));
    }
}

class Person
{
    int age;
}

这是因为java有内存优化机制,-127到128之间的整数,都预先分配了内存地址
所以age一开始是18时指向一个地址,改为0后指向了另一个地址
python也有类似的机制
这不仅在成员变量里存在
你定义两个int a,b,然后给它们赋相同的值,会发现它们地址一样
这种机制的好处在于,假如你搞了一堆指示灯变量,来回修改它们的值,一会0一会1一会2
那么即使定义了1000个变量,后面其实指向的只是3个地址,而不是1000个不同的地址
这样在你大量定义数值非常小的变量时,可以有效的节约内存

b不就是a传过去的吗,后面age变了,所以属性地址就变了,你最后面再打印a和b的属性地址,你也会发现是一样的

其实最主要的还是看变量的地址