使用第三方 API,我观察到以下内容。
而不是使用,
public static string getString(){
return "Hello World";
}
它使用类似的东西
public static void getString(String output){
}
我正在分配“输出”字符串。
我很好奇实现这种功能的原因。使用这样的输出参数有什么好处?
使用第三方 API,我观察到以下内容。
而不是使用,
public static string getString(){
return "Hello World";
}
它使用类似的东西
public static void getString(String output){
}
我正在分配“输出”字符串。
我很好奇实现这种功能的原因。使用这样的输出参数有什么好处?
你的例子有些不对劲。
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<T> {
public Holder(T value) {
this.value = value;
}
public T value;
}
然后你可以绕过持有人:
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"
}
这个例子是错误的,Java 没有输出参数。
你可以做的一件事来模仿这种行为是:
public void doSomething(String[] output) {
output[0] = "Hello World!";
}
但是恕我直言,这在多个层面上都很糟糕。:)
如果你想要一个方法返回一些东西,让它返回它。如果您需要返回多个对象,请创建一个容器类来将这些对象放入并返回。
我不同意 Jasper:“在我看来,这是返回多个结果的一种非常丑陋和糟糕的方式”。在 .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 中不存在的项目。有时这是必要的。
这个功能有一个很大的缺点——它不起作用。函数参数是函数的局部参数,分配给它们不会在函数之外产生任何影响。
另一方面
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();
}
如果您有一个管理器使用单个请求调用多个句柄,您可以更改请求的状态以允许(由其他处理程序)对修改后的内容进行进一步处理。经理也可以决定停止处理。
好处:
实际上,在 java 中不可能有参数,但是您可以通过编写一个泛型类,其中不可变是具有 value 和 setter 的泛型,使该方法对不可变 String 和原语进行取消引用和 getter 或使用数组,其中元素 0(长度为 1)是提供它首先实例化的值,因为在某些情况下,您需要返回多个值,而必须编写一个类只是为了将它们返回到类所在的位置只用过,只是浪费文本,不能真正重复使用。
现在是 C/C++ 和 .Net(单声道或 MS),它敦促我 Java 至少不支持对原语的取消引用;所以,我改用数组。
这是一个例子。假设您需要创建一个函数(方法)来检查数组中的索引是否有效,但您还想在索引验证后返回剩余的长度。让我们在 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++ 中的 'template bool tryToGetArray (SomeObject* p, T** ppArray)' 或C#'bool tryToGetArray(SomeObject o, ref T[] array)'。只要 [][] 或 [] 首先在内存中使用至少一个元素进行实例化,它就可以正常工作。
在我看来,当您在一个函数中有多个结果时,这很有用。