Java中的输出参数

使用第三方API,我观察到以下内容。

而不是使用,

public static string getString(){ return "Hello World"; } 

它使用类似的东西

 public static void getString(String output){ } 

我正在分配“输出”字符串。

我很好奇实现这种function的原因。 使用这些输出参数有什么好处?

你的例子中有些东西是不对的。

 class Foo { public static void main(String[] args) { String x = "foo"; getString(x); System.out.println(x); } public static void getString(String output){ output = "Hello World" } } 

在上面的程序中,将输出字符串“foo”, 而不是 “Hello World”。

某些类型是可变的,在这种情况下,您可以修改传递给函数的对象。 对于不可变类型(例如String ),您必须构建某种可以传递的包装类:

 class Holder { public Holder(T value) { this.value = value; } public T value; } 

然后你可以绕过持有人:

 public static void main(String[] args) { String x = "foo"; Holder h = new Holder(x); getString(h); System.out.println(h.value); } public static void getString(Holder output){ output.value = "Hello World" } 

我不同意贾斯帕:“在我看来,这是一个非常丑陋和糟糕的方式来回报不止一个结果”。 在.NET中,有一个有趣的结构使用输出参数:

 bool IDictionary.TryGet(key, out value); 

我发现它非常有用和优雅。 如果一个项目在收集中并且同时返回它,它是最方便的方式。 有了它你可以写:

 object obj; if (myList.TryGet(theKey, out obj)) { ... work with the obj; } 

如果我看到旧式代码,我会经常责骂我的开发人员:

 if (myList.Contains(theKey)) { obj = myList.Get(theKey); } 

你看,它将性能降低了一半。 在Java中,无法区分现有项的空值与一次调用中Map中项的不存在。 有时这是必要的。

这个例子是错误的,Java没有输出参数。

您可以做的一件事就是模仿这种行为:

 public void doSomething(String[] output) { output[0] = "Hello World!"; } 

但恕我直言,这在多个层面上很糟糕。 🙂

如果你想要一个方法返回一些东西,让它返回它。 如果需要返回多个对象,请创建一个容器类以将这些对象放入并返回该对象。

此function有一个很大的缺点 – 它不起作用。 函数参数是函数的本地函数,并且赋值给它们在函数外部没有任何影响。
另一方面

 void getString(StringBuilder builder) { builder.delete(0, builder.length()); builder.append("hello world"); } 

会工作,但我认为没有这样做的好处(除非你需要返回多个值)。

字符串是不可变的,您不能将Java的伪输出参数与不可变对象一起使用。

此外, 输出范围仅限于getString方法。 如果更改输出变量,调用者将看不到任何内容。

但是,您可以做的是更改参数的状态 。 请考虑以下示例:

 void handle(Request r) { doStuff(r.getContent()); r.changeState("foobar"); r.setHandled(); } 

如果您有一个管理器使用单个请求调用多个句柄,您可以更改请求的状态以允许(通过其他处理程序)对已修改的内容进行进一步处理。 经理也可以决定停止处理。

优点:

  • 您不需要返回包含新内容的特殊对象以及是否应该停止处理。 该对象仅使用一次并创建对象浪费内存和处理能力。
  • 您不必创建另一个Request对象,让垃圾收集器摆脱现在过时的旧引用。
  • 在某些情况下,您无法创建新对象。 例如,因为该对象是使用工厂创建的,并且您无权访问它,或者因为该对象具有侦听器而您不知道如何告诉正在侦听旧请求的对象应该改为听取新的请求。

实际上,在java中输出参数是不可能的,但你可以通过编写一个generics类来使该方法对不可变的String和原语进行去引用,其中不可变的是generics的值和setter和getter或使用一个数组,其中元素0(长度为1)是提供的值,它首先实例化,因为在某些情况下你需要返回多个值,必须编写一个类只是为了返回它们在类的位置只使用它只是浪费文本而不是真正可重复使用。

现在是C / C ++和.Net(单声道或MS),它促使我不支持至少对基元的去引用; 所以,我采用arrays代替。

这是一个例子。 假设您需要创建一个函数(方法)来检查索引是否在数组中有效,但您还希望在validation索引后返回剩余长度。 我们在c中将其称为’bool validate_index(int index,int arr_len,int&rem)’。 在java中执行此操作的方法是’Boolean validate_index(int index,int arr_len,int [] rem1)’。 rem1只表示数组中包含1个元素。

 public static Boolean validate_index(int index, int arr_len, int[] rem1) { if (index < 0 || arr_len <= 0) return false; Boolean retVal = (index >= 0 && index < arr_len); if (retVal && rem1 != null) rem1[0] = (arr_len - (index + 1)); return retVal; } 

现在,如果我们使用它,我们可以获得布尔返回和余数。

  public static void main(String[] args) { int[] ints = int[]{1, 2, 3, 4, 5, 6}; int[] aRem = int[]{-1}; //because we can only scapegoat the de-ref we need to instantiate it first. Boolean result = validate_index(3, ints.length, aRem); System.out.println("Validation = " + result.toString()); System.out.println("Remainding elements equals " + aRem[0].toString()); } 

puts:Validation = True puts:剩余元素等于2

数组元素始终指向堆栈上的对象或堆上对象的地址。 因此,即使对于数组,使用它作为去引用也是绝对可能的,因为它使它成为一个双数组,将其实例化为myArrayPointer = new Class [1] []然后将其传入,因为有时你不知道数组的长度是多少直到调用通过像'Boolean tryToGetArray(SomeObject o,T [] [] ppArray)'这样的算法,它与c / c ++中的模拟bool tryToGetArray(SomeObject * p,T ** ppArray)'或C#'bool tryToGetArray(SomeObject o,ref T [] array)'。 只要[] []或[]首先在内存中实例化至少一个元素,它就能正常工作。

有时这种机制可以避免创建新对象。

示例:如果无论如何都存在适当的对象,将它传递给方法并更改一些字段会更快。

这比在被调用方法中创建新对象,返回并分配其引用(生成需要在某个时间收集的垃圾)更有效。

在我看来,当你在一个函数中有多个结果时,这很有用。