Reputation: 25
I'm creating a program to automatize the train logical system, using Java. I want store trains with ArrayList:
ArrayList<Treni> train = new ArrayList<>();
and add a multiple stations to the train list:
ArrayList<Fermata> stop= new ArrayList<>();
stop.add(new Stop("Milan", "7", new DepartureTime((byte) 19, (byte) 35)));
train.add(new Train(87569, "Trenitalia", fermata));
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<Fermata> 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;
}
}```
Upvotes: 1
Views: 202
Reputation: 338574
The Answer by Zidek is correct, and should be accepted. Here I will give some example code, while rewriting for brevity.
You can define your classes more briefly as records. Records are appropriate for classes whose main purpose is to communicate data transparently and immutably.
You can use List.of
to instantiate an unmodifiable List
object.
Rather than invent your own type for time-of-day, use java.time.LocalTime
.
By the way, a train number should be of type String (or a custom class), not an integer type. The train number is really a train identifier, not a quantity nor an ordinal.
This code is untested, written in an iPhone, so may need some editing.
public record Train( int number, String owner, List<Stop> stops ) {}
public record Stop( String station, String binary, LocalTime departure, LocalTime arrival ) {}
List< Train > trains =
List.of(
new Train(
87569,
"Trenitalia",
List.of(
new Stop( "Milan", "7", LocalTime.of( 19 , 35 ), null ) ,
new Stop( "Venice", "7", LocalTime.of( 20 , 55 ) , null )
)
) ,
… new Train( … )
);
If you need a list to be modifiable, instantiate ArrayList
. But note that you can pass to its constructor a list produced by List.of
. This technique makes for compact readable literals-style syntax.
List< Person > persons =
new ArrayList <>(
List.of(
new Person( "Alice" ) ,
new Person( "Bob" ) ,
new Person( "Carol" )
)
)
;
Upvotes: 2
Reputation: 4034
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:
Instead of calling clear on the stop
list, you create a new instance, by calling new ArrayList<Stop>
.
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 );
Copied from the closed duplicate of this question.
Upvotes: 0
Reputation: 20026
The solution is suggested in the @f1sh's and @MCEmperor's comments.
For some reasons, there is a meme among the programmers, that creating a new object is always more costly than recycling an old one. This is what probably misleads you to use stop.clear()
instead of stop = new ArrayList<Stop>
.
By the way, it's a good practice to name list variables in plural, so stops
would be a much better name than stop
for a list of stops.
There is probably other misunderstanding in your question. The parameters in Java are always passed as "reference by value". So what you are passing to your train is a reference to a list. Your Train
object does not receive a copy of the list of stops, but just a reference to its memory representation in heap. So if you later change the content of the memory, your train refers to the new data.
On the other side, when you change the outside stops
variable, the original memory will remain the same.
So just do as @f1sh says: "just create a new List instead of clearing the old one: stops = new ArrayList<>();
"
Upvotes: 2