本篇文章记录一些本人关于值传递或引用传递的理解,补一补大学的基础,老泪纵横。有疑问还请怒怼。
1. 首先说一下关于对象的创建
Person me = new Person("Franklin") , 这句代码包含几个步骤:
1. new Person :代表在堆内存中为实际对象开辟空间;
2. ("Franklin") :代表给对象初始化;
3. Person me : 代表对象在堆中的地址,也可以叫引用,保存在栈内存中;
4. = : 代表将实际对象在堆中的内存地址赋值给了me
2. 弄清楚基本类型和引用类型
int a = 100; a是基本类型
String s = "sss"; s是引用类型
Java的8大数据类型,都属于基本类型。
对象都属于引用类型。
3. 弄清楚实参和行参
方法声明:
public void fun(int age , String name) {} // age 和 name 是行参
方法调用:
fun(25,"Franklin"); // 25 和 "Franklin"是实参
行参只在该方法被执行的时候,才会开辟内存。方法运行结束之后,行参会被销毁,内存被回收。
4. Java中的方法调用都是值传递
具体原因在这里很难说清楚,其实也不需要在这里纠结。我们只需要知道方法调用时,行参和实参的执行原理就行了。掌握了原理,以后自己写代码或者“去造火箭”都是可以轻松拿下的。
5. 示例
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public void setInformation(int age, String name) {
this.age = age;
this.name = name;
}
}
先预告一笔,setInformation方法很重要。
private static void changeInfo (Person p1, Person p2) {
Person tempPerson = p1;
p1 = p2;
p2 = tempPerson;
p1.setInformation(50,"王五");
p2 = new Person(60,"赵六");
}
public static void main(String[] args) {
Person p1 = new Person(30,"张三");
Person p2 = new Person(40,"李四");
changeInfo(p1, p2);
Log.d("Franklin", p1.name + "," + p1.age + "\n" + p2.name + "," + p2.age)
}
不要往下拉,你觉得应该打印什么呢?
一步步分析:
-
先创建p1 和 p2两个对象的引用,他俩分别指向堆内存中的张三和李四;
-
changeInfo(p1,p2)将引用传入方法。请注意:在java中给方法传引用都是传的引用的copy。 意思就是现在栈内存中有p1和p1' 两个引用指向了张三,有p2和p2' 两个引用指向李四;
-
在changeInfo方法中的前三行代码,很明显是一个交换值的操作,即p1'和p2' 所指向的对象交换。所以目前是 p1和 p2' 指向张三,p2和p1' 指向李四;
-
继续 p1.setInfomation(50,"王五"),这句很强势。它代表:使用对象自己的可以改变自身属性的方法来改变自己。这句话应该好懂吧!还是举几个例子: List的add方法 、 StringBuilder的append方法。 这句话执行之后,p1' 所指向的李四就隐姓埋名了,改成了50岁的王五。多说一句:此时内存中p2指向不受影响,还是指王五,也就是之前的李四;
-
最后p2 = new Point(80,"赵六") 这句代码和我们刚开始第一节对象的创建一样啊。所以这时候 p2' 就不指向张三啦,p2' 指向的是系统在堆中重新创建的一个赵六的对象。
-
分析完了最后再总结一下,此时栈和堆之间的指向关系:
p1 -> 张三
p2 -> 王五
p1' -> 王五
p2' -> 赵六
而changeInfo方法走完之后,copy出来的临时指针p1'和p2' 会被销毁,内存回收。堆中没有被指针指的赵六,就被视为垃圾,也会被回收。 -
最终日志打印出来就是
张三,30
王五,50
看到这,是不是有种恍然大明白的感觉???
总结一句话:
如果对象没有改变自己的方法,通过行参无法改变对象。
网友评论