简体   繁体   中英

How to return reference to object as parameter in Java

Although I've programmed C, C++ and C# for many years I'm am only superficially familiar with Java. Helping my Comp Sci son with a Java college project he had a need to return references to two objects from a method in Java. I suggested returning one as the function value and the 2nd as a reference. He wasn't sure how to do this. I did a little research and realized it may not be possible. My question is in Java what is the common method used when a method needs to return more than one reference to an object. Here's the specific example in my sons case.

// This method returns references to the head and tail objects from the passed in 
// linked list.  The head object is returned as the function value and the tail is 
// returned as a parameter.
public Static Node GetHeadTail(List list, Node tail)

I realize the above doesn't work in Java since the tail is a reference to node and in Java the reference itself is passed by value. What is the most common way of dealing with this in Java? My son's solution was to return an array of 2 Node objects for the function value. I said that was a poor solution because it doesn't document the meaning of each element of the array. Another solution would be to create an object that contained the head and tail references. However in the particular example it was the head pointer that was of most interest and if an object was returned it would create undesired coding overhead for the caller of the method if all they wanted was the head.

In this case, java programmers would commonly create a class with 2 members: head and tail . That would be the return type for the getHeadTail(List list) method.

You can only pass by value in Java. Your best solution is the second one your son suggested, ie return an object that has the head and tail.

Java is always pass-by-value. The difficult thing can be to understand that Java passes objects as references and those references are passed by value. ( Is Java "pass-by-reference" or "pass-by-value"? )

However, you are capable of doing something like this:

public static void main(String[] args)
{
    Car c = new Car("Blue");
    System.out.println(c.getName());
    changer(c);
    System.out.println(c.getName());
}

public static void changer(Car c)
{
    c.setName("Red");
}

The Car class.

public class Car 
{
    private String name;

    public Car(String n)
    {
        name = n;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String n)
    {
        name = n;
    }
}

The output will be:

Blue
Red

Knowing this, you will be able to change what tail points to and still be able to return the head .

Java does this interesting thing that's sort of a hybrid between pass-by-value and pass-by-reference. Basically, a parameter cannot be changed by the function, but the function can ask the parameter to change itself via calling some method within it. This answer does a pretty good job of explaining it.

In response to "What is the most common way of dealing with this in Java?" your solution of creating a class that contains a head and tail reference is probably the most common and best practice. If possible, it may even be best to just have separate getHead and getTail methods.

One slightly less obvious solution: Use one of the built-in types, like Queue or LinkedList, which already has a head and tail.

LinkedList list = new LinkedList();
head = list.getFirst();
tail = list.getLast();

There's a bunch of types like this one depending on your need. Read the docs.

A somewhat hacky technique is to use a an array as a parameter. Then, the function can change the value of one or more element to "return" it. It's not pretty but gets the job done and avoids the need to create special wrapper objects for this purpose.

Just as a side note, Scala solves this issue by letting you return tuples.

If you are trying to implement a method that return multiple values as arguments, you can use something like this:

public class Future<T> {
  private T instance;

  public T get() {
    return this.instance;
  }

  public void set(T value) {
    this.instance = value;
  }
}

And use it like this:

class MyCrazyClass {

  private static void myCrazyMethod(Future<String> returnVal1, Future<Integer> returnVal2, Future<Float> returnVal3) {
    returnVal1.set("We are cool!");
    returnVal2.set(123);
    returnVal3.set(321F);
  }

  public static void main(String[] args) {
    Future<String> strRetVal = new Future<>();
    Future<Integer> intRetVal = new Future<>();
    Future<Float> floatRetVal = new Future<>();

    myCrazyMethod(strRetVal, intRetVal, floatRetVal);

    System.out.println(strRetVal.get());
    System.out.println(intRetVal.get());
    System.out.println(floatRetVal.get());
  }
}

Output:

We are cool!
123
321.0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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