如何在 Java 中使用引用?

Posted

技术标签:

【中文标题】如何在 Java 中使用引用?【英文标题】:How to use references in Java? 【发布时间】:2011-06-10 09:54:38 【问题描述】:

我想在 Java 中使用引用,但我不知道怎么做! 例如在 C++ 中我们这样写:

void sum(int& x)

    ...

但是在 Java 中 & 符号是编译器错误! 请帮助我理解 Java 中的引用。

【问题讨论】:

***.com/questions/40480/is-java-pass-by-reference见上面的帖子 @Esko,除非您编辑帖子只是为了进行小的外观修复(例如更正错字)。我发现 @skaffman 以那种“语气”发表他的评论,而另外 6 人投票认为它有帮助,我感到很沮丧。 @Tim:实际上,我确实记得从官方博客和元数据中阅读了与您刚才所说的完全相反的内容。在我看来,修正错别字和语法是得到认可的,因为有时它会让其他人更容易理解问题本身。 @Esko,你是对的,但现在我更郁闷了。 Is Java pass by reference?的可能重复 【参考方案1】:

对象默认通过引用传递对象通过引用访问,但是没有办法创建对原始值(byte、short、int、长)。您要么必须创建一个对象来包装整数,要么使用单个元素数组。

public void sum(int[] i)
   i[0] = ...;

public void sum(MyInt i)
   i.value = ...;

public class MyInt
   public int value; 

对于您的示例,类似以下的内容可能会起作用

public int sum(int v)
   return ...;

public int sum()
   return ...;

更新:

对象引用的附加/更好的描述:

Java 对象总是通过引用来访问。与原始类型一样,此引用按值传递(例如,复制)。由于程序员在 java 中可以访问的所有内容都是通过复制传递的(引用、基元),并且无法创建对基元类型的引用,因此对方法参数(引用、基元)的任何修改只会影响本地副本方法。 可以在方法中修改对象,因为引用的两个副本(本地和其他)仍然指向同一个对象实例。

示例:

在方法内修改原语,这只影响 i 的内部副本,而不影响传递的值。

void primitive(int i)
  i = 0;

修改方法内的引用,这只影响ref的内部副本,不影响传递的值。

 void reference(Object ref)
    ref = new Object();//points to new Object() only within this method
 

修改一个对象,全局可见

void object(List l)
   l.add(new Object());//modifies the object instead of the reference

上面的数组和MyInt都是基于对象的修改。

【讨论】:

“默认情况下,对象是通过引用传递的”——这是错误的。 Java 中的一切都是按值传递的。令人困惑的地方是 references(非原始变量)也是 by value 传递的。请注意,通过值传递引用与通过引用传递对象不同。 @Jesper 并没有完全错误,对象总是在 java 中通过引用传递。引用本身是按值传递的也是如此。 不能直接传递对象。非原始类型的变量是引用——它们不是对象本身,就像在 C++ 中一样。当您谈论 Java 时,谈论“传递对象”是不准确的术语。 @Jesper 你能帮我定义一下“通过”吗,看来我的英语水平还不够。 "pass" 在此上下文中意味着您将变量用作方法调用中的参数。但重点不在于“通过”这个词,而在于 Java 中的变量是引用,并不像 C++ 中那样直接表示对象。【参考方案2】:

普通的 Java 参数已经更接近于 C++ 引用,而不是 C++ 值传递或指针传递。所以,你所有的 Java 方法都已经是这样了。

然而,

int 和其他原语在 Java 中是特殊的;以上对对象引用是正确的。


编辑:更准确地说,正如@fatih 所说,所有 Java 调用都是按值传递的。然而,当你传递一个对象时,你传递的是一个值引用。因此,作为第一个近似值,上面的陈述是正确的:普通的 Java 参数更类似于 C++ 引用,而不是 C++ 值传递或指针传递。

【讨论】:

【参考方案3】:

了解 Java 的按值传递语义必读:

http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html http://javadude.com/articles/passbyvalue.htm http://javachannel.net/wiki/pmwiki.php/FAQ/PassingVariables(链接到其他几个页面)

彻底消除 Java 可以通过引用传递任何内容的想法。让我们看一个例子,好吗?

public class App

    public static void main( String[] args )
    
        Foo f1 = new Foo();
        doSomethingToFoo(f1);
        System.out.println(f1.bar); //Hey guess what, f1.bar is still 0 because JAVA IS PASS BY VALUE!!!
    

    static void doSomethingToFoo(Foo f) 
        f = new Foo();
        f.bar = 99;
    

    static class Foo 
        int bar = 0;
    

【讨论】:

如果删除f = new Foo() 的行会怎样?我猜你会打印 99,而不是 0。【参考方案4】:

Apache Commons 中的 MutableInt 类会做你想做的事,尽管它并不漂亮。

MutableInt

void sum(MutableInt mx)

    int x = mx.getValue();
    x = ...
    mx.setValue(x);


...

MutableInt mx = new MutableInt(5);
sum(mx);
int result = mx.getValue();

为其他基本类型和对象提供了额外的类。

创建一个额外的对象只是为了提供一个参考会涉及一些开销,所以解决方案不是最佳的,但在大多数情况下你应该没问题。

通常,最好找到一种方法从方法返回结果。不幸的是,Java 只允许以这种方式返回一个值。

【讨论】:

以上是关于如何在 Java 中使用引用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在java中使用来自另一个bundle的OSGI引用

我们可以在java中使用引用传递吗?如果否 java.util.Arrays.sort 如何工作?

如何在 Java 8 中引用 reduce() 操作的结果?

如何在没有引用的情况下访问 Java 堆对象?

如何使用 java spring 注释在 MongoDB 中创建一个完全填充的引用对象

如何在 Java 中引用目录?