转载: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);
}
}
|