我希望语义类似于C#中的ref关键字。
Java 看起来很混乱,因为所有东西都是按值传递。然而对于一个引用类型的参数(即不是原始类型的参数),它是通过按值传递引用本身的方式进行传递,因此它看起来像是按引用传递(并且人们经常声称它是)。但事实并非如此,如下所示:
Object o = "Hello";
mutate(o)
System.out.println(o);
private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!
将会在控制台上打印Hello
。如果想让上面的代码打印Goodbye
,那么可以使用显式引用,如下所示:
AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!
private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }
我能在Java中通过引用传递参数吗?
不行。
为什么?Java只有一种传递方法的模式:按值传递。
注意:
对于基本类型,这很容易理解:你得到一个值的副本。
对于其他所有类型,你得到一个引用的副本,这也被称为按值传递。
这就是全部内容:
在Java中,与ref相似的语言层面上没有任何东西。在Java中,只有按值传递的语义
出于好奇,您可以通过将对象包装在可变类中来实现类似于ref的语义:
public class Ref<T> {
private T value;
public Ref(T value) {
this.value = value;
}
public T get() {
return value;
}
public void set(T anotherValue) {
value = anotherValue;
}
@Override
public String toString() {
return value.toString();
}
@Override
public boolean equals(Object obj) {
return value.equals(obj);
}
@Override
public int hashCode() {
return value.hashCode();
}
}
测试用例:
public void changeRef(Ref<String> ref) {
ref.set("bbb");
}
// ...
Ref<String> ref = new Ref<String>("aaa");
changeRef(ref);
System.out.println(ref); // prints "bbb"
AtomicReference
(非原始类型)?或者对于原始类型,使用AtomicSomething
(例如:AtomicBoolean
)呢? - Arvinint
而不是Integer
,bool
而不是Boolean
等等?也就是说,包装类(如果您担心语法,它们会自动解包)不起作用吗? - Paul Stelian来自《Java编程语言》的James Gosling:
"……在Java中,参数传递只有一种方式——按值传递——这使事情保持简单。"
我认为你不能这样做。你最好的选择可能是将想要通过引用传递的东西封装在另一个类实例中,并通过值传递(外部)类的引用。如果你明白我的意思...
也就是说,你的方法会改变它所传递的对象的内部状态,这个改变会对调用者可见。
Java始终按值传递。
当您传递一个基本类型时,它是该值的副本;当您传递一个对象时,它是该引用指针的副本。
void method(SomeClass[] v) { v[0] = ...; }
但是,1)必须在调用方法之前初始化数组,2)仍然无法以这种方式实现交换方法...
JDK中使用了这种方式,例如在java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[])
中。请查看我在https://dev59.com/q2DVa4cB1Zd3GeqPeYlC#9324155中的回答。
在那里,我使用了一个更简单的包装类思想。我不喜欢将setter/getter作为标准。当没有理由隐藏一个字段时,我会将其设置为“public”。特别是在这种情况下。
然而,这对于原始类型或多参数/类型返回值除外,其他都可以工作:
public class Ref<T> {
public T val;
}
虽然,我想你可以只添加更多的类型参数。但是我认为创建一个适合目的的内部静态类会更容易:
public static class MyReturn {
public String name;
public int age;
public double salary;
}
这将用于当您不需要它进行其他操作时。
MyReturn mRtn = new MyReturn();
public void myMethod(final MyReturn mRtn){
mRtn.name = "Fred Smith";
mRtn.age = 32;
mRtn.salary = 100000.00;
}
System.out.println(mRtn.name + " " +mRtn.age + ": $" + mRtn.salary);