【问题标题】:How to do "call by reference" in Java?如何在 Java 中进行“引用调用”?
【发布时间】:2011-05-17 09:42:38
【问题描述】:
  1. 如何在 Java 中进行“引用调用”? (假设我们使用该术语的方式与自 1960 年代以来在同行评审的 CS 文献中使用的方式相同;请参阅 this Wikipedia page 以获得简单的解释。)

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

【问题讨论】:

  • 从目前的答案来看,我猜这个问题是模棱两可的。您能否提供一个 C 或 C++ 示例来说明您想要实现的目标?
  • 以交换两个数字为例......正如 Stephen C 给出的......在 Java 中是否可能???
  • 查看我之前的回答:stackoverflow.com/questions/3624525/…
  • 我试图通过提出关于经典传递引用和传递函数指针的问题(实际上按值传递引用)来解决歧义。跨度>

标签: java function-call


【解决方案1】:

在 Java 中,真正的传递引用是不可能的。 Java 通过值传递所有内容,包括引用。但是你可以用容器对象来模拟它。

使用其中任何一个作为方法参数:

  • 一个数组
  • 一个集合
  • AtomicXYZ 类

如果你在一个方法中改变了它的内容,改变的内容将在调用上下文中可用。


糟糕,您显然是指通过引用调用方法。这在 Java 中也是不可能的,因为方法在 Java 中不是第一级公民。 This may change in 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

【讨论】:

  • 我认为您的意思是通过引用传递。我认为 OP 是在询问使用方法引用的调用方法。 ;)
  • +1 以获得全面的答案,涵盖 OP 问题的所有可能含义!
【解决方案2】:

如何在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 架构中不存在这个概念。


如何在 Java 中像在 C 和 C++ 中那样通过引用调用函数??

重要提示:这不是“引用调用”。它是使用对函数的引用的“按值调用”1

在 Java 8 之前,不支持将函数引用作为值。因此,您不能将它们作为参数传递,也不能将它们分配给变量。

但是,您可以使用一个实例方法定义一个类,并使用该类的实例而不是函数引用。其他答案给出了这种方法的例子。

从 Java 8 开始,方法引用支持使用 :: 语法。方法参考有4种:

  • 引用静态方法:ContainingClass::staticMethodName
  • 对特定对象的实例方法的引用:containingObject::instanceMethodName
  • 对特定类型的任意对象的实例方法的引用:ContainingType::methodName
  • 对构造函数的引用:ClassName::new

1 - 从教学的角度来看,不幸的是 C 和 C++ 使用 & 符号来表示引用调用和表示函数指针。但是,从语言设计的角度来看,我并不反对这种设计选择。

【讨论】:

【解决方案3】:

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

Collections.sort(list, new Comparator() {

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

});

【讨论】:

  • 您可以修改list 的唯一原因是通过list 的方法。如果参数是ints,接口没有帮助。 OP指的是能够通过形参修改实参。
【解决方案4】:
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

【讨论】:

    【解决方案5】:

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

    // 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);
    

    【讨论】:

      【解决方案6】:

      在 Java 中,除了原语,将 Object 传递给方法/函数总是通过引用。 示例见Oli Charlesworth's answer

      对于原始类型,您可以使用数组来包装它: 例如:

      public void foo(int[] in){
        in[0] = 2;
      }
      
      int[] byRef = new int[1];
      byRef[0] = 1;
      foo(byRef);
      // ==> byRef[0] == 2.
      

      【讨论】:

      • 在数组中包装原始类型确实有效。查看带有 jgf 包的代码:
      • 很多人混淆了“按引用调用”和“按值传递对象引用”。在 Java 中,它始终是“按值调用”。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

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

        所以要做到这一点,如上所述,您可以使用数组、集合

        【讨论】:

          【解决方案9】:

          http://www.javaworld.com/javaqa/2000-05/03-qa-0526-pass.html

          Java 确实通过引用来操作对象,并且所有对象变量都是引用。但是,Java 不会通过引用传递方法参数。它按值传递它们。

          【讨论】:

          • 虽然如此,但需要注意一件非常重要的事情:传递的 对象的引用
          【解决方案10】:

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

          【讨论】:

          • 我现在拥有大约 5 本关于 Java 的书籍。坦率地说,大多数作者在写书方面都很糟糕,他们对 Java 语言的掌握充其量是值得怀疑的。
          • 撰写引用文本的作者不理解“引用调用”的真正含义。通过引用调用意味着将引用传递给变量。说传递对变量的引用和对对象的引用“实际上是同一件事”就像说汽车和自行车实际上是同一件事。
          【解决方案11】:

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

          【讨论】:

            【解决方案12】:

            是的,您可以通过“按引用传递”以另一种方式实现按引用调用。

            • 您应该传递所创建类的引用对象。
            • 然后可以通过成员函数(.)对对象的数据进行操作,这将反映在原始数据中。

            在下面的代码中,原始数据 --> 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

            【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-11-29
            • 1970-01-01
            • 2011-01-11
            • 2019-09-27
            • 1970-01-01
            • 1970-01-01
            • 2011-02-11
            相关资源
            最近更新 更多