Java 中的输出参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1403921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Output Parameters in Java
提问by Chathuranga Chandrasekara
With a third party API I observed the following.
使用第三方 API,我观察到以下情况。
Instead of using,
而不是使用,
public static string getString(){
return "Hello World";
}
it uses something like
它使用类似
public static void getString(String output){
}
and I am getting the "output" string assigned.
我正在分配“输出”字符串。
I am curious about the reason of implementing such functionality. What are the advantages of using such output parameters?
我很好奇实现这种功能的原因。使用这样的输出参数有什么好处?
采纳答案by Adam Batkin
Something isn't right in your example.
你的例子有些不对劲。
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"
}
}
In the above program, the string "foo" will be output, not"Hello World".
在上面的程序中,将输出字符串“foo”,而不是“Hello World”。
Some types are mutable, in which case you can modify an object passed into a function. For immutable types (such as String
), you would have to build some sort of wrapper class that you can pass around instead:
某些类型是可变的,在这种情况下,您可以修改传递给函数的对象。对于不可变类型(例如String
),您必须构建某种可以传递的包装类:
class Holder<T> {
public Holder(T value) {
this.value = value;
}
public T value;
}
Then you can instead pass around the holder:
然后你可以绕过持有者:
public static void main(String[] args) {
String x = "foo";
Holder<String> h = new Holder(x);
getString(h);
System.out.println(h.value);
}
public static void getString(Holder<String> output){
output.value = "Hello World"
}
回答by Tadeusz Kopec
This functionality has one big disadvantage - it doesn't work. Function parameters are local to function and assigning to them doesn't have any impact outside the function.
On the other hand
这个功能有一个很大的缺点——它不起作用。函数参数是函数的本地参数,分配给它们不会在函数之外产生任何影响。
另一方面
void getString(StringBuilder builder) {
builder.delete(0, builder.length());
builder.append("hello world");
}
will work, but I see no advantages of doing this (except when you need to return more than one value).
会起作用,但我认为这样做没有任何好处(除非您需要返回多个值)。
回答by Bombe
That example is wrong, Java does not have output parameters.
那个例子是错误的,Java 没有输出参数。
One thing you could do to emulate this behaviour is:
你可以做的一件事是模仿这种行为:
public void doSomething(String[] output) {
output[0] = "Hello World!";
}
But IMHO this sucks on multiple levels. :)
但恕我直言,这在多个层面上都很糟糕。:)
If you want a method to return something, make it return it. If you need to return multiple objects, create a container class to put these objects into and return that.
如果你想要一个方法返回一些东西,让它返回它。如果您需要返回多个对象,请创建一个容器类将这些对象放入并返回。
回答by Curd
Sometimes this mechanism can avoid creation of a new object.
有时这种机制可以避免创建新对象。
Example: If an appropriate object exists anyhow, it is faster to pass it to the method and get some field changed.
示例:如果一个合适的对象无论如何存在,将它传递给方法并更改某些字段会更快。
This is more efficient than creating a new object inside the called method, and returning and assigning its reference (producing garbage that needs to be collected sometime).
这比在被调用的方法内创建一个新对象并返回和分配其引用(产生需要在某个时候收集的垃圾)更有效。
回答by Xr.
String are immutable, you cannot use Java's pseudo output parameters with immutable objects.
字符串是不可变的,您不能将 Java 的伪输出参数与不可变对象一起使用。
Also, the scope of outputis limited to the getStringmethod. If you change the outputvariable, the caller won't see a thing.
此外,输出范围仅限于getString方法。如果您更改输出变量,调用者将看不到任何内容。
What you can do, however, is change the stateof the parameter. Consider the following example:
但是,您可以做的是更改参数的状态。考虑以下示例:
void handle(Request r) {
doStuff(r.getContent());
r.changeState("foobar");
r.setHandled();
}
If you have a manager calling multiple handles with a single Request, you can change the state of the Request to allow further processing (by other handlers) on a modified content. The manager could also decide to stop processing.
如果您有一个管理器使用单个请求调用多个句柄,您可以更改请求的状态以允许对修改后的内容进行进一步处理(由其他处理程序)。经理也可以决定停止处理。
Advantages:
好处:
- You don't need to return a special object containing the new content and whether the processing should stop. That object would only be used once and creating the object waste memory and processing power.
- You don't have to create another Request object and let the garbage collector get rid of the now obsolete old reference.
- In some cases, you can'tcreate a new object. For example, because that object was created using a factory, and you don't have access to it, or because the object had listeners and you don't know how to tell the objects that were listening to the old Request that they should instead listen to the new Request.
- 您不需要返回包含新内容以及处理是否应停止的特殊对象。该对象只会被使用一次,并且创建该对象会浪费内存和处理能力。
- 您不必创建另一个 Request 对象并让垃圾收集器摆脱现在已经过时的旧引用。
- 在某些情况下,您无法创建新对象。例如,因为该对象是使用工厂创建的,而您无权访问它,或者因为该对象有侦听器而您不知道如何告诉正在侦听旧请求的对象应该改为听新的请求。
回答by Davide Consonni
in my opinion, this is useful when you have more than one result in a function.
在我看来,当您在一个函数中有多个结果时,这很有用。
回答by plinyar
I disagree with Jasper: "In my opinion, this is a really ugly and bad way to return more than one result". In .NET there is a interesting construct that utilize the output parameters:
我不同意 Jasper:“在我看来,这是返回多个结果的一种非常丑陋和糟糕的方式”。在 .NET 中有一个利用输出参数的有趣结构:
bool IDictionary.TryGet(key, out value);
I find it very usefull and elegant. And it is the most convenient way to aks if an item is in collection and return it at the same time. With it you may write:
我觉得它非常有用和优雅。这是查询物品是否在收藏中并同时返回的最方便的方法。有了它,你可以写:
object obj;
if (myList.TryGet(theKey, out obj))
{
... work with the obj;
}
I constantly scold my developers if I see old-style code like:
如果我看到像这样的旧式代码,我会不断地责骂我的开发人员:
if (myList.Contains(theKey))
{
obj = myList.Get(theKey);
}
You see, it cuts the performance in half. In Java there is no way to differentiate null value of an existing item from non-existance of an item in a Map in one call. Sometimes this is necessary.
你看,它把性能减半。在 Java 中,无法在一次调用中区分 Map 中现有项目的空值与不存在的项目。有时这是必要的。
回答by bvrwoo_3376
Actually, it is impossible to have out parameters in java but you can make a work around making the method take on a de-reference for the immutable String and primitives by either writing a generic class where the immutable is the generic with the value and setter and getter or by using an array where element 0 (1 in length) is the value provided it is instantiate first because there are situations where you need to return more than one value where having to write a class just to return them where the class is only used there is just a waste of text and not really re-usable.
实际上,在 Java 中不可能有参数,但是您可以通过编写一个泛型类来解决使该方法对不可变字符串和原语进行取消引用的方法,其中不可变是具有值和设置器的泛型和 getter 或使用数组,其中元素 0(长度为 1)是值,前提是它首先被实例化,因为在某些情况下,您需要返回多个值,而必须编写一个类来返回它们所在的类只用在那里只是浪费文本,而不是真正可重用。
Now being a C/C++ and also .Net (mono or MS), it urges me that java does not support at least a de-reference for primitives; so, I resort to the array instead.
现在是 C/C++ 和 .Net(单声道或 MS),它敦促我 Java 至少不支持对原语的取消引用;所以,我改用数组。
Here is an example. Let's say you need to create a function (method) to check whether the index is valid in the array but you also want to return the remainding length after the index is validated. Let's call it in c as 'bool validate_index(int index, int arr_len, int&rem)'. A way to do this in java would be 'Boolean validate_index(int index, int arr_len, int[] rem1)'. rem1 just means the array hold 1 element.
这是一个例子。假设您需要创建一个函数(方法)来检查索引在数组中是否有效,但您还想在索引验证后返回剩余长度。让我们在 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;
}
Now if we use this we can get both the Boolean return and the remainder.
现在,如果我们使用它,我们可以获得布尔返回值和余数。
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: Remainding elements equals 2
puts: Validation = True puts: 剩余元素等于 2
Array elements always either point to the object on the stack or the address of the object on the heap. So using it as a de-references is absolutely possible even for arrays by making it a double array instantiating it as myArrayPointer = new Class[1][] then passing it in because sometimes you don't know what the length of the array will until the call going through an algorithm like 'Boolean tryToGetArray(SomeObject o, T[][] ppArray)' which would be the same as in c/c++ as 'template bool tryToGetArray (SomeObject* p, T** ppArray)' or C# 'bool tryToGetArray(SomeObject o, ref T[] array)'. It works and it works well as long as the [][] or [] is instantiate in memory first with at least one element.
数组元素要么指向堆栈上的对象,要么指向堆上对象的地址。因此,即使对于数组,使用它作为取消引用也是绝对可能的,方法是使其成为一个双数组,将其实例化为 myArrayPointer = new Class[1][] 然后将其传入,因为有时您不知道数组的长度是多少直到调用通过像 'Boolean tryToGetArray(SomeObject o, T[][] ppArray)' 这样的算法,这与 c/c++ 中的 'template bool tryToGetArray (SomeObject* p, T** ppArray)' 或C# 'bool tryToGetArray(SomeObject o, ref T[] array)'。只要 [][] 或 [] 首先使用至少一个元素在内存中实例化,它就可以工作并且运行良好。