'Stack an ArrayList [duplicate]

I'm creating a program to automate the train logistics system, using Java. I want store trains with ArrayList:

ArrayList<Train> train = new ArrayList<>();

and add a multiple stations to the train list:

ArrayList<Stop> stop= new ArrayList<>();
stop.add( new Stop( "Milan", "7", new DepartureTime( (byte) 19, (byte) 35 ) ) );
train.add( new Train( 87569, "Trenitalia", stop ) );

Now i want to clear all stops to add a new stops:

stop.clear();

but with this method it clear the stops in entire class Train. How can I store the ArrayList stop and use the method clear() without lose stops in the Train class?

This is Train.java:

public class Train{
  private int number;
  private String owner;
  private ArrayList<Stop> stop = new ArrayList<>();

  Train(int number, String owner, ArrayList<Stop> stop) {
    this.number = number;
    this.owner = owner;
    this.stop = stop;
  }
}

class Stop{
  String station, binary;
  DepartureTime departure;
  ArrivalTime arrival;

  Stop(String station, String binary, DepartureTime departure, ArrivalTime arrival) {
    this.station= station;
    this.binary= binary;
    this.departure= departure;
    this.arrival= arrival;
  }

  Stop(String station, String binary, DepartureTime departure) {
    this.station = station;
    this.binary= binary;
    this.departure= departure;
  }
}

class DepartureTime{
  private byte hour, minute;

  DepartureTime(byte hour, byte minute) {
    this.hour= hour;
    this.minute = minute;
  }

}

class ArrivalTime {
  private byte hour, minute;

  ArrivalTime (byte hour, byte minute) {
    this.hour= hour;
    this.minute = minute;
  }
}


Solution 1:[1]

You fell in a well known Java trap: the argument stop of the constructor Train(int,String,List<Stop>) is not an (instance of an) ArrayList, it is just the reference to such an instance.

This means that the statement

this.stop = stop;

in that constructor does not keep an instance of that List, but just a reference.

As a consequence you should have noticed that all trains would have exactly the same list of stops when you do omit the call to stop.clear().

You now have two options to fix this:

  1. Instead of calling clear on the stop list, you create a new instance, by calling new ArrayList<Stop>.

  2. The recommended approach (as the first one is far from being bullet proof …) looks like this:

public class Train
{
  private final int number;
  private final String owner;
  private final List<Stop> stop;

  Train( final int number, final String owner, final List<Stop> stop ) 
  {
    this.number = number;
    this.owner = owner;
    this.stop = List.copyOf( stop );
  }
}

If you want to manipulate the stops later, you can also write

this.stop = new ArrayList<>( stop );

Solution 2:[2]

Even though stop is added train it is still the same reference you're clearing. So, Create a shallow copy of the Stop ArrayList and add it to Train, something like this.

 public static void main(String[] args) throws IOException, GeneralSecurityException {
        ArrayList<Train> train = new ArrayList<>();
        ArrayList<Stop> stop= new ArrayList<>();
        stop.add(new Stop("Milan", "7", new DepartureTime((byte) 19, (byte) 35)));

        ArrayList<Stop>  copyStop = new ArrayList<>(stop);
        train.add(new Train(87569, "Trenitalia", new ArrayList<>(copyStop)));
        stop.clear();

    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 HariHaravelan