简体   繁体   English

当您需要在Java中通过引用传递为多个参数赋值时,您是如何做到的?

[英]When you need pass by reference in Java to assign values to multiple parameters, how do you do it?

In order to refactor some methods into smaller ones, I need pass by reference, since I can only have one return type. 为了将一些方法重构为较小的方法,我需要通过引用传递,因为我只能有一个返回类型。 I could create a different return or parameter type whenever I need to do this, but then I'd end up with a bunch of bloated, seemingly unnecessary classes. 每当我需要这样做时,我都可以创建一个不同的返回或参数类型,但后来我最终得到了一堆臃肿的,看似不必要的类。

What is the best alternative here, besides redesigning the program, which can't be done? 除了重新设计程序之外,这里最好的选择是什么呢?

edit: some of it CAN be redesigned, and that's what I am doing, but, for example, at one point it is finding the minimum and second minimum values in a huge collection and then manipulating them. 编辑:其中一些可以重新设计,这就是我正在做的事情,但是,例如,它在一个点上找到一个巨大的集合中的最小和第二最小值,然后操纵它们。 I wanted to split that into 2 methods - one finds, another manipulates - but it seems highly unlikely I'll be able to do this cleanly. 我想把它分成两个方法 - 一个发现,另一个操纵 - 但我似乎不太可能干净地做到这一点。

You are talking about "returning" multiple values by means of so-called out parameters, like you sometimes find in C, which are passed by reference? 您正在谈论通过所谓的out参数“返回”多个值,就像您有时在C中找到的那样,它们是通过引用传递的?

You asked for an alternative to returning a single value class, but that is really the right thing to do. 你想要一个返回单个值类的替代方法,但这确实是正确的。

But since you ask, yes, you're correct that you need a little more work to get pass-by-reference semantics in Java. 但是,既然你问,是的,你是正确的,你需要更多的工作来获得Java中的pass-by-reference语义。 Java is always pass-by-value (yes I mean that -- it is object references that are passed into methods, and those are passed by value). Java总是按值传递(是的,我的意思是 - 它是传递给方法的对象引用 ,并且它们是通过值传递的)。 So to fake pass-by-reference, you could do something like pass an array of one Object, and change the reference it contains, if you wanted to pass back a new reference this way. 因此,如果你想以这种方式传回一个新的引用,你可以做一些像传递一个Object的数组,并更改它包含的引用。

However I'd call this highly unconventional and would not recommend it. 但是,我称之为高度非常规,并不会推荐它。 Any improvement you get by refactoring is destroyed by this. 通过重构获得的任何改进都会被破坏。

I need pass by reference 我需要通过引用传递

To be strictly precise, Java does not have pass by reference. 严格来说,Java没有通过引用传递。 There's only one passing mechanism in Java, and that's pass by value. Java中只有一种传递机制,它是通过值传递的。

In the case of objects, the thing that's being passed is not the object itself, which lives on the heap. 在对象的情况下,传递的东西不是生成在堆上的对象本身。 It's the reference to the object that's passed by value. 它是对值传递的对象的引用。

It might sound like a nitpick, but it's an important one. 这可能听起来像一个挑剔,但它是一个重要的。

I don't see what this has to do with refactoring. 我不知道这与重构有什么关系。 If you need to create new types just to be returned, by all means do so. 如果您需要创建新类型以便返回,请务必执行此操作。 I'd bet that you really don't have an object model that reflects the problem at hand, which is why you have this refactoring problem. 我敢打赌,你真的没有反映手头问题的对象模型,这就是你有这个重构问题的原因。

Doesn't sound very object-oriented to me, especially after reading your edit. 对我来说听起来不太面向对象,特别是在阅读你的编辑之后。

You could do something like create a generic class that could handle out values from a function. 你可以做一些事情,比如创建一个可以处理函数值的泛型类。

private static class OutValue<T> {
    public T value;

    static <X> OutValue<X> makeOutValue(X value) {
        OutValue<X> outValue = new OutValue<X>();
        outValue.value = value;
        return outValue;
    }
}

Here is an example of how the class could be used to get an integer from a function. 下面是一个如何使用类从函数中获取整数的示例。

void getInteger(OutValue<Integer> x)
{
    x.value = 1;
}

OutValue<Integer> outValue = OutValue.makeOutValue(0);
getInteger(outValue);
System.out.println("value = " + outValue.value);

It is probably not the most elegant overall solution, but it will keep you from having to write a ton of classes if you do not want to do a more involved refactor. 它可能不是最优雅的整体解决方案,但如果你不想做一个更复杂的重构,它将使你不必编写大量的类。

bunch of bloated, seemingly unnecessary classes. 一堆臃肿,看似不必要的课程。

Hmm either the data belong together, which is why you have decided to return them from a single method, or they don't. 嗯,要么数据属于一个,这就是为什么你决定从单一方法返回它们,或者他们没有。 If they do, isn't a new class is appropriate? 如果他们这样做,是不是新班级合适? As a last ditch you could return a Vector. 作为最后一个沟,你可以返回一个Vector。

edit 编辑

or if you always had a finite number of return items you could use something like Pair<T1,T2> (or define some such generic tuple type) 或者如果你总是有一个有限数量的返回项,你可以使用像Pair<T1,T2> (或定义一些这样的通用元组类型)

Promote your variables to instance variables, that way they'll be visible to both methods (you are allowed to have state in an object after all). 将变量提升为实例变量,这两种方法都可以看到它们(毕竟你可以在对象中拥有状态)。 If they don't look like they should belong on your object then I don't think you'll be able to get around a redesign. 如果他们看起来不应该属于你的对象,那么我认为你无法绕过重新设计。

Since in a method, the arguments the references of objects are passed by value, couldn't you do something along the lines of: 因为在一个方法中,对象引用的参数是按值传递的,所以你不能按照以下方式做一些事情:

import java.awt.Point;

public class Example {
    public static void main(String args[]) {
        Point pnt1 = new Point(0, 0);
        Point pnt2 = new Point(0, 0);
        System.out.println("X: " + pnt1.x + " Y: " + pnt1.y);
        System.out.println("X: " + pnt2.x + " Y: " + pnt2.y);
        System.out.println(" ");
        sillyMethod(pnt1, pnt2);
        System.out.println("X: " + pnt1.x + " Y: " + pnt1.y);
        System.out.println("X: " + pnt2.x + " Y: " + pnt2.y);
    }

    public static void sillyMethod(Point arg1, Point arg2) {
        arg1.x = 100;
        arg1.y = 100;
        arg2.x = 200;
        arg2.y = 200;
    }
}

This way, you are changing the values of the objects, without returning diverging types. 这样,您将更改对象的值,而不返回分歧类型。

Without more detail, it's difficult to give specific advice. 没有更多细节,很难给出具体的建议。 But possibilities include: 但可能性包括:

Put related functions into a single class and make the data member variables. 将相关函数放入单个类中并生成数据成员变量。 Like to take your "find and minipulate two smallest": 喜欢把你的“发现和微小的两个最小”:

class ManipulateLeast2
{
  List<int> list;
  int firstSmallest;
  int secondSmallest;

  public ManipulateLeast2(List<int> list)
  {
    this.list=list;
  }
  public void findTwoSmallest()
  {
     .. scan list and populate firstSmallest and secondSmallest ...
  }
  public void processTwoSmallest()
  {
     ... process firstSmallest and secondSmallest and do whatever ...
  }
}

If that's awkward, another possibility is to create a class to hold the values you need and return that. 如果这很尴尬,另一种可能性就是创建一个类来保存你需要的值并返回它。 Like: 喜欢:

public class Smallest
{
  int first;
  int second;
  public Smallest(int first, int second)
  {
    this.first=first;
    this.second=second;
  }
}
...
public Smallest findSmallest(List list)
{
  ... find two smallest and put in first and second ...
  // Create the object and return it
  return new Smallest(first, second);
}

I think this is much superior to faking out a pass-by-reference. 我认为这比伪造传递参考要好得多。 But if you really insist, it could be done by putting the value in a wrapper, like this: 但如果你真的坚持,可以通过将值放在包装器中来完成,如下所示:

public StringWrapper
{
  public String s;
}
...
// callee
void getTwoStrings(StringWrapper sw1, StringWrapper sw2)
{
  sw1.s="Hello";
  sw2.s="Goodbye";
} 
// caller
StringWrapper sw1=new StringWrapper();
StringWrapper sw2=new StringWrapper();
getTwoStrings(sw1, sw2);
System.out.println("First is "+sw1.s);
System.out.println("Second is "+sw2.s);

To make this clean you'd need a separate wrapper for each class. 为了使其清洁,您需要为每个类单独包装。 I suppose you could make an ObjectWrapper to make it generic and then cast things, but this is getting quite messy. 我想你可以制作一个ObjectWrapper来使它成为通用的,然后再投射东西,但这变得非常混乱。

I think you're much better off to think of how your data relates and move it into logical classes. 我认为你最好考虑一下你的数据如何相关并将其转化为逻辑类。

Just because a method can only have one return type doesn't mean that that type can't contain more than one piece of information. 仅仅因为一个方法只能有一个返回类型并不意味着该类型不能包含多个信息。 The solution to the type of problem you seem to be having is to declare data types which hold multiple pieces of information. 您似乎遇到的问题类型的解决方案是声明包含多条信息的数据类型。

Following the example in the question ("finding the minimum and second minimum values in a huge collection and then manipulating them"): 按照问题中的示例(“在一个巨大的集合中找到最小值和第二个最小值,然后操纵它们”):

public class MinimumHolder {
    private int min;
    private int secondMin;
    public MinimumHolder(int min, int secondMin) {
        this.min = min;
        this.secondMin = secondMin;
    }

    //getters...
}

public MinimumHolder findTwoMinimums(Set<Integer> numbers) {
    // ...
    return new MinimumHolder(...);
}

public MinimumHolder manipulateData(MinimumHolder mins) {
    // do stuff with the data, this method could also be
    // declared as void if MinimumHolder was mutable
}

You could also pretty easily refactor MinimumHolder so that it could hold a variable list of "minimums" which were exposed with a getMinimum(int position) if you ever wanted to find more than two minimums. 您还可以非常轻松地重构MinimumHolder以便它可以保存一个“最小值”的变量列表,如果您想要找到两个以上的最小值,则使用getMinimum(int position)公开。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM