32
  1. 如何在 Java 中进行“引用调用”?(假设我们使用该术语的方式与自 1960 年代以来在同行评审的 CS 文献中使用的方式相同;请参阅此 Wikipedia 页面以获得简单的解释。)

  2. 既然 Java 不支持指针,那怎么可能像我们在 C 和 C++ 中那样在 Java 中通过引用来调用函数?

4

12 回答 12

41

在 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,因此您可以轻松地替换SomeFooOtherFoo.

于 2011-05-17T09:44:35.390 回答
13

如何在 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++ 使用该&符号来表示引用调用和表示函数指针。但是,从语言设计的角度来看,我并不反对这种设计选择。

于 2011-05-17T10:07:38.063 回答
3

通常在java中这是通过使用接口来解决的:

Collections.sort(list, new Comparator() {

  @Override
  public int compareTo(Object o1, Object o2) {
  /// code
  }

});
于 2011-05-17T09:46:17.193 回答
2
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
于 2013-09-11T16:57:44.057 回答
1

Java 只允许按值调用。但是,可以使用按值调用将对对象的引用转移到被调用函数。如果这些引用用于在被调用函数中操作对象的数据,则此更改在调用函数中也将可见。我们不能像使用指针那样对引用进行指针运算,但引用可以使用句点运算符指向对象的数据,该运算符在 C/C++ 中用作“*”运算符。

于 2014-03-22T07:59:31.650 回答
1

最好的方法是使用执行操作的接口。

// 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);
于 2011-05-17T09:45:56.593 回答
1

在 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.
于 2011-05-17T09:54:11.407 回答
1

JAVA 确实允许使用对象进行内部引用。当一个人写这个作业时 Obj o1 = new Obj(); 对象o2=o1;它有什么作用,o1 和 o2 都指向同一个地址。操纵任何物体的空间,也会反映在另一个物体的空间中。

所以要做到这一点,如上所述,您可以使用 Array、Collections

于 2016-12-16T06:05:18.417 回答
0

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.

于 2012-09-10T13:35:39.703 回答
0

来自 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”。

于 2014-08-20T11:28:27.193 回答
0

您不能在 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];

    }

    }
于 2020-06-19T13:12:25.983 回答
-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

于 2019-11-26T11:16:06.863 回答