当你需要在Java中通过引用传递给多个参数赋值时,你该怎么做?

发布于 2024-08-31 01:23:49 字数 248 浏览 8 评论 0原文

为了将一些方法重构为更小的方法,我需要通过引用传递,因为我只能有一种返回类型。每当我需要这样做时,我都可以创建不同的返回或参数类型,但最终我会得到一堆臃肿的、看似不必要的类。

除了重新设计程序之外,最好的替代方案是什么?

编辑:其中一些可以重新设计,这就是我正在做的事情,但是,例如,在某一时刻,它是在一个巨大的集合中找到最小值和第二最小值,然后操纵它们。我想将其分为两种方法 - 一种是发现,另一种是操纵 - 但我似乎不太可能干净利落地做到这一点。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

℉絮湮 2024-09-07 01:23:49

您正在谈论通过所谓的输出参数“返回”多个值,就像您有时在 C 中找到的那样,这些值是通过引用传递的?

您要求提供返回单个值类的替代方案,但这确实是正确的做法。

但既然你问了,是的,你是对的,你需要做更多的工作来获得 Java 中的按引用传递语义。 Java 总是按值传递(是的,我的意思是——对象引用被传递到方法中,并且这些是按值传递的)。因此,要伪造按引用传递,如果您想以这种方式传回新的引用,您可以执行一些操作,例如传递一个对象的数组,并更改它包含的引用。

不过我认为这是非常非常规的,并且不会推荐它。通过重构获得的任何改进都会被破坏。

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?

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 is always pass-by-value (yes I mean that -- it is object references that are passed into methods, and those are passed by value). 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.

However I'd call this highly unconventional and would not recommend it. Any improvement you get by refactoring is destroyed by this.

夜空下最亮的亮点 2024-09-07 01:23:49

我需要通过引用传递

严格来说,Java 没有按引用传递。 Java 中只有一种传递机制,那就是按值传递。

对于对象来说,传递的不是对象本身,它位于堆上。它是对按值传递的对象的引用。

这听起来可能有点挑剔,但它很重要。

我不明白这与重构有什么关系。如果您需要创建新类型只是为了返回,请务必这样做。我敢打赌,您确实没有反映当前问题的对象模型,这就是您遇到重构问题的原因。

对我来说听起来不太面向对象,尤其是在阅读了您的编辑之后。

I need pass by reference

To be strictly precise, Java does not have pass by reference. There's only one passing mechanism in Java, and that's pass by value.

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.

剑心龙吟 2024-09-07 01:23:49

您可以做一些事情,例如创建一个可以处理函数中的值的泛型类。

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;
    }
}

下面是如何使用该类从函数获取整数的示例。

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

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

它可能不是最优雅的整体解决方案,但如果您不想进行更复杂的重构,它将使您不必编写大量类。

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.

梦晓ヶ微光ヅ倾城 2024-09-07 01:23:49

将您的变量提升为实例变量,这样它们对两种方法都是可见的(毕竟您可以在对象中拥有状态)。如果它们看起来不应该属于您的对象,那么我认为您将无法绕过重新设计。

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.

疯狂的代价 2024-09-07 01:23:49

由于在方法中,参数和对象的引用是按值传递的,因此您不能执行以下操作:通过

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;
    }
}

这种方式,您可以更改对象的值,而不返回不同的类型。

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.

A君 2024-09-07 01:23:49

一堆臃肿的、看似不必要的类。


数据要么属于一起,这就是您决定从单个方法返回它们的原因,要么不属于一起。如果他们这样做了,是不是一个新的班级是合适的?
作为最后的手段,你可以返回一个 Vector。

编辑

或者如果您总是有有限数量的返回项,您可以使用类似 Pair (或定义一些此类通用元组类型)

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.

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)

一抹微笑 2024-09-07 01:23:49

如果没有更多细节,很难给出具体的建议。但可能性包括:

将相关函数放入一个类中,并将数据成员变量。就像你的“找到并最小化两个最小的”:

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 ...
  }
}

如果这很尴尬,另一种可能性是创建一个类来保存你需要的值并返回它。就像:

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);
}

我认为这比伪造引用传递要优越得多。但如果您真的坚持,可以通过将值放入包装器中来完成,如下所示:

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);

为了使其干净,您需要为每个类使用单独的包装器。我想你可以制作一个 ObjectWrapper 使其通用,然后进行转换,但这变得非常混乱。

我认为您最好考虑一下数据如何关联并将其移入逻辑类。

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.

I think you're much better off to think of how your data relates and move it into logical classes.

青朷 2024-09-07 01:23:49

仅仅因为一个方法只能有一个返回类型并不意味着该类型不能包含多于一条信息。您似乎遇到的问题类型的解决方案是声明保存多条信息的数据类型。

按照问题中的示例(“在一个巨大的集合中查找最小值和第二最小值,然后操作它们”):

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
}

您还可以很容易地重构 MinimumHolder ,以便它可以保存一个变量列表“如果您想找到两个以上的最小值,则可以使用 getMinimum(intposition) 公开该最小值。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文