引用

转载:https://www.cnblogs.com/shoshana-kong/p/10822538.html

指针是一种变量,其中存储了地址信息,可以操作其中的地址来变换指针指向的变量,也可以进入其中的地址来修改被指变量本身。Java中去除了指针的概念,使用引用这个概念。

引用是什么

package chapter3Demos;

import source.Hero;

public class Demo3_3_2 {

    public static void main(String[] args)  {
        Hero h = new Hero();
        System.out.println(h);
    }
    
}

打印结果source.Hero@15db9742

我们知道,在new一个对象时,new返回了一个新对象的引用,并将其存入等号左边的对象变量中。也就是说,h是一个Hero对象的引用。从上例我们不难发现,h中存储的是一个地址,也就是说本质上,引用也是指向对象的指针,但是只能操作对象本身,不能更改指针的指向,也没有了内存泄漏的危险。

引用的细节

既然引用中存储的是对象的地址,那么当有两个引用指向一个对象时,更改对象的状态,两个引用都会变化吗?

package chapter3Demos;

import source.Hero;

public class Demo3_3_2 {

    public static void main(String[] args)  {
        Hero h = new Hero();
        System.out.println(h.getHp());
        Hero hero = h;
        h.setHp(4);
        System.out.println("h的血量:"+h.getHp());
        System.out.println("hero的血量:"+hero.getHp());

      System.out.println(h);
      System.out.println(hero);


    }
}

打印结果:

5
h的血量:4
hero的血量:4

 source.Hero@15db9742
 source.Hero@15db9742

我们可以看到,这段代码先声明了h作为一个新hero的引用,然后把h的值赋给了hero,当我们改变h中hp的值时,通过hero打印出的hp也发生了变化。且打印h和hero中存储的内容得到的是相同的地址内容。所以我们可以判断,h和hero指向了同一个Hero对象,同一块内存空间。相当于一台电视机,先有了一个遥控器h,又复制了另一个遥控器hero。

下面是另一个实例

String cat1="little cat";
String cat2="little cat";
String cat3=new String("little cat");
System.out.println(cat1==cat2);
System.out.println(cat1==cat3);
————————————————
版权声明:本文为CSDN博主「华-山」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mountain_hua/article/details/88777672

打印结果:

true
false

我们先创建了一个cat1,并且内存中也有“little cat”了,这个时候如果用这种方式String cat2="little cat"创建cat2的话,Java虚拟机就会发现内存中已经存在“little cat”这个对象了(当然在创建cat1时也会检查内存中有没有“little cat”),就会直接把cat2指向“little cat”所在内存。所以cat1和cat2是指向同一个对象的引用,他们当然相等啦。

然鹅,由于cat3的创建方式是通过new String("little cat")来创建的,这个时候就会在内存区域(准确的说是堆内存中)中新开辟一块内存空间创建对象“little cat”,与cat1操纵的对象在不同的内存地址(尽管内容相同)。cat1与cat3就是指向不同内存地址的遥控器(引用)了,当然不相等啦。

 

引用传递和按值传递的区别

public class ReferencePkValue2 {
     
    public static void main(String[] args) { 
        ReferencePkValue2 t = new ReferencePkValue2(); 
        int a=99; 
        t.test1(a);//这里传递的参数a就是按值传递 
        System.out.println(a);
         
        MyObj obj=new MyObj(); 
        t.test2(obj);//这里传递的参数obj就是引用传递
        System.out.println(obj.b);
    } 
     
    public void test1(int a){ 
        a=a++;
        System.out.println(a);
        } 
     
    public void test2(MyObj obj){ 
        obj.b=100;
        System.out.println(obj.b);
        }
}

输出是

99
99
100
100

可以看到,int值没有发生变化,但是在test2方法中对obj类做的修改影响了obj这个对象。

这里要特殊考虑String,以及Integer、Double等几个基本类型包装类,它们都是immutable类型,
因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待,可以认为是和基本数据类型相似,传值操作。

结合上面的分析,关于值传递和引用传递可以得出这样的结论:

(1)基本数据类型传值,对形参的修改不会影响实参;
(2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;
(3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。

  参考https://www.cnblogs.com/menmenz/p/11756857.html

看一个例子:

1
2
3
class MyObj{
    public int b=99;
}

分别传参int和对象类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ReferencePkValue2 {
     
    public static void main(String[] args) { 
        ReferencePkValue2 t = new ReferencePkValue2(); 
        int a=99
        t.test1(a);//这里传递的参数a就是按值传递 
        System.out.println(a);
         
        MyObj obj=new MyObj(); 
        t.test2(obj);//这里传递的参数obj就是引用传递
        System.out.println(obj.b);
    
     
    public void test1(int a){ 
        a=a++;
        System.out.println(a);
        
     
    public void test2(MyObj obj){ 
        obj.b=100;
        System.out.println(obj.b);
        }
}
原文地址:https://www.cnblogs.com/Joey777210/p/11753476.html