如何在 Java 中进行“引用调用”?(假设我们使用该术语的方式与自 1960 年代以来在同行评审的 CS 文献中使用的方式相同;请参阅此 Wikipedia 页面以获得简单的解释。)
既然 Java 不支持指针,那怎么可能像我们在 C 和 C++ 中那样在 Java 中通过引用来调用函数?
12 回答
在 Java 中,真正的传递引用是不可能的。Java 通过值传递所有内容,包括引用。但是你可以用容器对象来模拟它。
使用其中任何一个作为方法参数:
- 数组
- 一个集合
- AtomicXYZ 类
如果您在方法中更改其内容,则更改的内容将可用于调用上下文。
糟糕,您显然是指通过引用调用方法。这在 Java 中也是不可能的,因为方法在 Java 中不是第一级公民。这在 JDK 8 中可能会发生变化,但目前,您将不得不使用接口来解决此限制。
public interface Foo{
void doSomeThing();
}
public class SomeFoo implements Foo{
public void doSomeThing(){
System.out.println("foo");
}
}
public class OtherFoo implements Foo{
public void doSomeThing(){
System.out.println("bar");
}
}
在您的代码中使用Foo
,因此您可以轻松地替换SomeFoo
为OtherFoo
.
如何在 Java 中进行引用调用?
您不能在 Java 中通过引用进行调用。时期。甚至没有什么能接近。并且按值传递引用与按引用调用不同。
(真正的“引用调用”允许你做这种事情:
void swap(ref int i, ref int j) { int tmp = *i; *i = *j; *j = tmp }
int a = 1;
int b = 2;
swap(a, b);
print("a is %s, b is %s\n", a, b); // -> "a = 2, b = 1"
在 Java 中你根本无法做到这一点。)
由于Java不支持指针...
虽然这在技术上是正确的,但它不会成为您尝试做的事情的障碍。
Java确实支持引用,这在最重要的方面就像指针。不同之处在于,您不能通过对它们进行算术运算、将它们与整数类型相互转换等等来将引用视为内存地址。而且您不能创建对变量的引用,因为 Java 或 JVM 体系结构中不存在这个概念。
如何像在 C 和 C++ 中那样在 Java 中通过引用调用函数?
重要提示:这不是“通过引用调用”。它是使用对函数1的引用的“按值调用” 。
在 Java 8 之前,不支持对函数的引用作为值。因此,您不能将它们作为参数传递,也不能将它们分配给变量。
但是,您可以使用一个实例方法定义一个类,并使用该类的实例而不是函数引用。其他答案给出了这种方法的例子。
::
从 Java 8 开始,使用语法支持方法引用。有4种方法参考:
- 引用静态方法:
ContainingClass::staticMethodName
- 引用特定对象的实例方法:
containingObject::instanceMethodName
- 引用特定类型的任意对象的实例方法:
ContainingType::methodName
- 对构造函数的引用:
ClassName::new
1 - 从教学的角度来看,不幸的是 C 和 C++ 使用该&
符号来表示引用调用和表示函数指针。但是,从语言设计的角度来看,我并不反对这种设计选择。
通常在java中这是通过使用接口来解决的:
Collections.sort(list, new Comparator() {
@Override
public int compareTo(Object o1, Object o2) {
/// code
}
});
package jgf;
public class TestJavaParams {
public static void main(String[] args) {
int[] counter1 = new int[1];
counter1[0] = 0;
System.out.println(counter1[0]);
doAdd1(counter1);
System.out.println(counter1[0]);
int counter2 = 0;
System.out.println(counter2);
doAdd2(counter2);
System.out.println(counter2);
}
public static void doAdd1(int[] counter1) {
counter1[0] += 1;
}
public static void doAdd2(int counter2) {
counter2 += 1;
}
}
输出将是:
0
1
0
0
Java 只允许按值调用。但是,可以使用按值调用将对对象的引用转移到被调用函数。如果这些引用用于在被调用函数中操作对象的数据,则此更改在调用函数中也将可见。我们不能像使用指针那样对引用进行指针运算,但引用可以使用句点运算符指向对象的数据,该运算符在 C/C++ 中用作“*”运算符。
最好的方法是使用执行操作的接口。
// Pass a Runnable which calls the task() method
executor.submit(new Runnable() {
public void run() {
task();
}
});
public void task() { }
您可以使用反射来调用任何方法
Method method = MyClass.class.getMethod("methodToCall", ParameterType.class);
result = method.invoke(object, args);
在 Java 中,除了原语,将 Object 传递给方法/函数总是通过引用。有关示例,请参见Oli Charlesworth 的答案。
对于原始类型,您可以使用数组对其进行包装:例如:
public void foo(int[] in){
in[0] = 2;
}
int[] byRef = new int[1];
byRef[0] = 1;
foo(byRef);
// ==> byRef[0] == 2.
JAVA 确实允许使用对象进行内部引用。当一个人写这个作业时 Obj o1 = new Obj(); 对象o2=o1;它有什么作用,o1 和 o2 都指向同一个地址。操纵任何物体的空间,也会反映在另一个物体的空间中。
所以要做到这一点,如上所述,您可以使用 Array、Collections
http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.html
Java does manipulate objects by reference, and all object variables are references. However, Java doesn't pass method arguments by reference; it passes them by value.
来自 Herbert Shildt 第 9 版的 Java The Complete Reference:“当您将对象传递给方法时,情况会发生巨大变化,因为对象是通过有效的引用调用传递的。请记住,当您创建一个一个类类型,你只是创建一个对象的引用。因此,当你将此引用传递给一个方法时,接收它的参数将引用与参数所引用的对象相同的对象。这实际上意味着对象充当如果它们通过引用调用传递给方法。方法内部对象的更改确实会影响用作参数的对象。
package objectpassing;
public class PassObjectTest {
public static void main(String[] args) {
Obj1 o1 = new Obj1(9);
System.out.println(o1.getA());
o1.setA(3);
System.out.println(o1.getA());
System.out.println(sendObj1(o1).getA());
System.out.println(o1.getA());
}
public static Obj1 sendObj1(Obj1 o)
{
o.setA(2);
return o;
}
}
class Obj1
{
private int a;
Obj1(int num)
{
a=num;
}
void setA(int setnum)
{
a=setnum;
}
int getA()
{
return a;
}
}
操作:9 3 2 2
对 getA() 的最终调用显示在对方法 public static Obj1 sendObj1(Obj1 o) 的调用中更改了原始对象字段“a”。
您不能在 Java 中通过引用进行调用。时期。甚至没有什么能接近。并且按值传递引用与按引用调用不同。
我用一个数组来做到这一点......
package method;
import java.util.Scanner;
public class InterChange {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int a[]=new int[2];
System.out.println("Enter two values");
for(int i=0;i<2;i++) {
a[i]=sc.nextInt();
}
hange(a);
for(int i=0;i<2;i++) {
System.out.println(a[i]);
}
}
static int hange(int b[])
{
int temp;
temp=b[0];
b[0]=b[1];
b[1]=temp;
return b[0]&b[1];
}
}
是的,您可以通过“按引用传递”以另一种方式实现按引用调用。
- 您应该传递创建的类的引用对象。
- 然后可以通过成员函数(.)对对象的数据进行操作,这将反映在原始数据中。
在下面的代码中,原始数据 --> x 是通过传递引用对象来操作的。
public class Method_Call {
static int x=50;
public void change(Method_Call obj) {
obj.x = 100;
}
public static void main(String[] args) {
Method_Call obj = new Method_Call();
System.out.println(x);
obj.change(obj);
System.out.println(x);
}
}
输出:50 100