如何扩展 Java 以引入通过引用传递?

Java 是按值传递的。您如何修改语言以引入通过引用传递(或一些等效的行为)?

举个例子,比如

public static void main(String[] args) {
    String variable = "'previous String reference'";
    passByReference(ref variable);
    System.out.println(variable); // I want this to print 'new String reference'
}

public static void passByReference(ref String someString) {
    someString = "'new String reference'";
}

它(不带 )编译为以下字节码ref

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 'previous String reference'
       2: astore_1
       3: aload_1
       4: invokestatic  #3                  // Method passByReference:(Ljava/lang/String;)V
       7: return

  public static void passByReference(java.lang.String);
    Code:
       0: ldc           #4                  // String 'new String reference'
       2: astore_0
       3: return

处的代码将引用从变量加载到堆栈上。3:variable

我正在考虑的一种可能性是让编译器确定一个方法是通过引用传递的,可能带有 ,并更改该方法以接受一个Holder对象,该对象存储与我们的变量相同的引用。当方法完成并可能更改持有者中的引用时,调用方值上的变量将替换为持有者引用的值。ref

它应该编译为与此等效

public static void main(String[] args) {
    String variable = "'previous String reference'";
    Holder holder = Holder.referenceOf(variable);
    passByReference2(holder);
    variable = (String) holder.getReference(); // I don't think this cast is necessary in bytecode
    System.out.println(variable);
}

public static void passByReference(Holder someString) {
    someString.setReference("'new String reference'");
}

其中可能类似于Holder

public class Holder {
    Object reference;
    private Holder (Object reference) {
        this.reference = reference;
    }
    public Object getReference() {
        return this.reference;
    }
    public void setReference(Object reference) {
        this.reference = reference;
    }
    public static Holder referenceOf(Object reference) {
        return new Holder(reference);
    }
}

这在哪里会失败,或者你如何改进它?


答案 1

我在Java中看到的通过引用传递的常用习语是传递单元素数组,这将既保留运行时类型安全性(与经历擦除的泛型不同),又避免引入新类的需要。

public static void main(String[] args) {
    String[] holder = new String[1];

    // variable optimized away as holder[0]
    holder[0] = "'previous String reference'";

    passByReference(holder);
    System.out.println(holder[0]);
}

public static void passByReference(String[] someString) {
    someString[0] = "'new String reference'";
}

答案 2

要回答您的问题:

这在哪里会失败?

  1. 最终变量和枚举常量
  2. “特殊”引用,例如this
  3. 从方法调用返回的引用,或使用new
  4. 文本(字符串、整数等)

...可能还有其他人。基本上,仅当参数源是非最终字段或局部变量时,关键字才可用。与 一起使用时,任何其他源都应生成编译错误。refref

(1) 的示例:

final String s = "final";
passByReference(ref s);  // Should not be possible

(2) 的示例:

passByReference(ref this);  // Definitely impossible

(3) 的示例:

passByReference(ref toString());  // Definitely impossible
passByReference(ref new String("foo"));  // Definitely impossible

(4) 的示例:

passByReference(ref "literal");  // Definitely impossible

然后是赋值表达式,在我看来,这就像是一种判断:

String s;
passByReference(ref (s="initial"));  // Possible, but does it make sense?

同样有点奇怪的是,您的语法需要方法定义和方法调用的关键字。我认为方法定义就足够了。ref