在Java中将原始类型作为输出参数传递

Posted

技术标签:

【中文标题】在Java中将原始类型作为输出参数传递【英文标题】:Passing primitive types as out param in Java 【发布时间】:2011-01-14 12:35:52 【问题描述】:

我需要在从方法返回内容列表时返回/更新布尔值。 Java 不能返回元组,我不想为此创建一个单独的类,所以我想我会将 bool 作为输出参数传递。这就是我们的 C++ 客户端所做的,通过引用传递 bool。这适用于普通类,因为 java 对对象具有传递引用(请参阅Is Java "pass-by-reference" or "pass-by-value"? 对此进行很好的讨论)。但是像 Boolean 这样的“包装器”类将它们的原始值存储为不可变的,因此不能以这种方式更新。

使用布尔数组(只有一个条目)看起来很笨拙,但可能是最简单的方法。或者,可以返回布尔值并将创建的列表作为输出参数传回,而不是作为返回值 [但是 java 客户端偏离了 C++,最好它们保持基本相同的方法——仅供参考,C# 中也需要这个。 ]

【问题讨论】:

其实Java可以返回元组。您可以将返回值放入 java.util.List 或 java.util.Map 并返回。 仅供参考,请参阅下面关于 java 元组和返回 List 的混乱的答案中的 cmets。 【参考方案1】:

不,Java 没有对象的传递引用;它具有“按值传递引用”,这不是一回事。

您绝对不能将任何东西作为“out”参数或在 Java 中通过引用传递 - 尽管您可以在 C# 中。

你能把“布尔加号列表”封装成另一种类型吗?他们真的有关系吗?使用布尔数组绝对是丑陋的。您可以编写一个MutableBoolean 包装器类型 - 但同样,这很丑陋。通常我会说返回两件事表明该方法应该被拆分,但是当其中一个是布尔值时,它可能是相当合理的——比如 C# 中的 int.TryParse 等。

【讨论】:

@Jon - Java 通过 ref 传递对象,通过值传递原语。那是在 SCJP 上,我不确定您所说的“按值传递引用”是什么意思。如果将对象作为参数传递,修改对象并退出,则对象被更改。不存在实际对象的“副本”。 @Mech Software - 不 - 这不在 SCJP 考试中 - 因为它是错误的。 bobcat.webappcabaret.net/javachina/faq/07.htm#pas_Q5 @Mech:我什么时候说object被复制了? reference 被复制。 reference 是按值传递的。你从来没有真正传递过一个对象——你传递了一个引用。还有@Cincinnati Joe - 它根本不需要乱七八糟。 “按值传递引用”并不混乱或不准确。 @finnw: "pointer" 表示它是指内存中的物理地址,它当然不必如此。 “句柄”会好一些,尽管它在 Windows 中的含义略有不同。 “对象 ID”可能还不错。真正的“参考”一旦掌握就不算太糟糕,而且获取起来也很简单。 @finnw:“引用”是指针(en.wikipedia.org/wiki/Reference_%28computer_science%29)之类的通用术语。所以这是一个完全合理的术语。我不认为 C++ 所谓的引用一定是这个术语的非常标准的用法,但是由于很多人来自 C++,所以他们陷入了“引用”的这个含义。【参考方案2】:

正如你所说,Boolen 包装类是不可变的,所以你不能用它来接收你的输出变量。

传入一个新列表以接收列表结果并返回布尔值对我来说听起来最自然,但你有充分的理由;在多个实现中保持接口大致相同。

您可以通过创建自己的可变布尔值并传递对它的引用来解决此问题,例如:

public class Example 
    public class BooleanResult 
        private boolean result;

        public void setResult(boolean value)  result = value; 
        public boolean getResult()  return result; 
    

    // ....
    public List doSomething(BooleanResult out) 
        List list;
        boolean result;

        // ...

        out.setResult(result);

        return list;
    

并像这样使用它:

Example.BooleanResult out = new Example.BooleanResult();

List list = example.doSomething(out);

boolean result = out.getResult();

【讨论】:

是的,感谢您充实这一点(Jon 在他的回答中也提到了这一点)。我认为这就是我们要做的,因为它与我们的 C++ 版本非常匹配。【参考方案3】:

我需要在从方法返回内容列表时返回/更新布尔值。 Java 不能返回元组,我不想为此创建一个单独的类

我也遇到过同样的问题,恕我直言,最好的解决方案通常是:

忘掉烦恼,单独上课。

我曾经对此犹豫不决,但类是用来封装值的,所以继续吧。

很有可能,一旦你的函数返回了一个自定义类的实例,你会发现有非常适合该类的附加功能,或者可以使用该类作为参数或返回值的其他方法,并且很快类将非常有用:-)。

如果您真的不想这样做,您可以随时将所有内容填充到 java.util.List 或 java.util.Map 中并返回。但这真的很难看:-(我也这样做了,然后后悔了。起初看起来很简单,但随着代码的发展和增长,可读性会受到影响(是整数列表,然后是双精度数,还是反之亦然?)。类更有帮助。

注意:如果您觉得***常规课程太过分了,您可以使用nested class,这对于仅“本地使用”的课程非常有用。

【讨论】:

我碰巧看了我最近在 CodeMash 开发者大会上的笔记,并回忆起 Java Posse 的 Dick Wall 在一次简短的演讲中提到了这种情况。他在谈论 Scala 并说它支持返回类型的元组(他提到了将它们添加到 Java 中的有争议的愿望:***.com/questions/457775/does-java-need-tuples)。他说,在 Java 中,如果你定义一个新的“struct”类来返回多个东西,你必须用 equals 和 hashcode 方法完全实现它,并且应该测试它——这样一个简单的东西的开销。 @Cincinnati Joe:有趣的一点,谢谢。至于“用equals等完全实现”:我有点不同意。不实施(覆盖)那些是完全可以接受的。您只需要记住,您不应该在未检查它们是否正确实现的情况下在类上盲目使用 equals() / hashcode()。但这是一种不同的蠕虫罐头......【参考方案4】:

您不能将任何原始类型用作 Java 中的“out”参数。这不会在任何时候发生。

您也不能使用任何对象版本,例如布尔、整数、浮点数、双精度等,因为它们是不可变的。您可以做的是编写自己的类或在 commons-lang (http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/mutable/MutableBoolean.html) 中使用 MutableBoolean 之类的东西。

例如:

public void setTrue(MutableBoolean b) 
    b.setValue(Boolean.TRUE);

【讨论】:

【参考方案5】:

我为返回多个值所做的是将返回类型更改为返回一个对象数组。 [0] 可以是布尔值,[1] 可以是列表。

缺点是调用者必须知道从对象数组中适当地转换返回的对象,而编译器无法为您检查。

编辑:Here 是从 Java 返回一对值的 SO 答案。

【讨论】:

我喜欢配对的想法 - 一位同事指出 Google 收藏有一个配对,但它似乎不在他们的 1.0 版本中。 根据这个 Google Collections not 还没有 Pair 类:code.google.com/p/guava-libraries/issues/detail?id=203【参考方案6】:

正如 rsp 和许多其他人所提到的,它是不可变的。但是,在 Java 1.5 版中,作为 java.util.concurrent.atomic 包的一部分引入了一个名为 AtomicBoolean 的布尔变量。如果您不想创建类来处理此类琐碎问题,AtomicBoolean 是您的最佳选择。看看这个。运行下面的代码自己看看吧。

public static void main(String[] args) 
    AtomicBoolean value = new AtomicBoolean(false);
    System.out.println(value); // Prints false
    someMethod(value);
    System.out.println(value); // Prints true


void someMethod(AtomicBoolean a) 
    a.set(true);

【讨论】:

-1 因为对于原子参数正在实现的锁定机制,您将有一个开销,尽管它可能很小。它们应该用于克服并发问题。可变参数更适合这种情况。

以上是关于在Java中将原始类型作为输出参数传递的主要内容,如果未能解决你的问题,请参考以下文章

在java中将接口类型(不实现类类型)作为参数传递

java - 如何在java中将大于999 999 999的数字作为参数传递

在打字稿中将枚举类型作为参数传递

可以在 Swift 中将枚举类型名称作为参数传递吗?

如何在Java中将对象数组作为参数传递

如何在Java中将类作为参数传递?