我熟悉java中的引用概念,但在看到这段代码之后我很困惑
public class App
{
public static void main( String[] args )
{
Test t1 = new Test(1);
Test t2 = new Test(8);
App.doSomething(t1, t2);
System.out.print(t1.a);
System.out.print(t2.a);
}
public static void doSomething(Test t1, Test t2){
System.out.print(t1.a++);
System.out.print(t2.a++);
t1 = new Test(999);
t2 = new Test(888);
}
}
打印:
1
8
2
9
为什么主函数中“t1.a”和“t1.b”的值不变为888和999?
答案 0 :(得分:5)
Java没有引用调用。所有参数都按值传递 - 但是对于作为对象的参数,传递的“值”是对对象的引用。
因此,如果在方法中使用对该对象的本地引用来修改对象,它将修改同一对象。但是,如果为该局部变量赋值,则它不再具有对原始对象的引用,后续更改不会影响原始对象。
答案 1 :(得分:0)
这就是为什么你通常将你的方法参数设置为final - 以避免这种混淆:) findbugs实际上会产生关于这种效果的样式警告
答案 2 :(得分:0)
那是因为java参数总是pass-by-value
。
在您的示例中,您传递对对象的引用,但是此引用是按值传递的。换句话说,创建新的局部变量t1
并使用对象的引用进行初始化,该对象已在参数中传递。因此,当您为其分配new Test()
时,只有局部变量引用新对象。
答案 3 :(得分:0)
在Java中,一切都是通过价值传递的。 2 t1和t2的范围是不同的。一个在main()的范围内,另一个在doSomething()的范围内。所以它没有改为888或999的原因是因为一旦你离开doSomething()就不存在这些值。
答案 4 :(得分:0)
新手很难用这个,我会尝试以故事形式解释:
如果我让你用一个指向红色沙发的箭头借我的粘滞便笺(我的名字在顶部),你拿走我的粘滞便笺并擦掉我的箭头并将一个新箭头放到绿色沙发上。当你完成你的恶作剧时,我会在上面写上一个带有我名字的便利贴,指向绿色沙发。我的演讲被改变了。
但是,如果我借用我的名字借用我的粘滞便笺,上面有一个指向红色沙发的箭头,你把我的粘滞便笺放到一边,然后你做一个新的粘滞便笺把你的名字放在上面,然后你在它上面指着绿色的沙发,你完成了你的恶作剧,然后我的粘滞便笺没有改变,我的名字指向红色的沙发。您创建了我无法触及的便签。
当你将一个新对象塞入t1时,你没有销毁旧对象,因为你没有这样做的授权。你只需将它推到一边,然后创建一个新的,除了你以外没有人可以访问。
这一行:
t1 = new Test(999);
不删除旧的t1。您只需创建一个仅对方法本地的新t1,该方法在方法结束后进行垃圾回收。使用此行,您没有更改传入的参数,您创建了一个具有相同名称的新变量。