存储一个 ArrayList

Store an ArrayList

我正在创建一个程序来自动化火车逻辑系统,使用 Java。 我想用 ArrayList 存储火车:

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

并在火车列表中添加多个车站:

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

现在我想清除所有停靠点以添加新停靠点:

stop.clear();

但使用这种方法可以清除整个 class 列车的停靠点。我如何存储 ArrayList 停止并使用方法 clear(); 而不会在火车 class?

中丢失停止

这是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;
  }
}```

@f1sh 和@MCEmperor 的评论中建议了解决方案。

出于某些原因,程序员中有一个模因,即创建新对象总是比回收旧对象成本更高。这可能会误导您使用 stop.clear() 而不是 stop = new ArrayList<Stop>

顺便说一下,用复数命名列表变量是一个好习惯,因此对于停靠点列表,stopsstop 更好。

你的问题可能还有其他的误解。 Java 中的参数 总是 作为“按值引用”传递。所以你传递给火车的是对列表的引用。您的 Train 对象不会收到停靠点列表的副本,而只会收到对其在堆中的内存表示的引用。因此,如果您稍后更改内存的内容,您的火车将引用新数据。

另一方面,当你更改外部stops变量时,原来的内存将保持不变。

所以就像@f1sh 说的那样:“只需创建一个新列表而不是清除旧列表:stops = new ArrayList<>();

是正确的,应该接受。在这里我将给出一些示例代码,同时为简洁起见重写。

您可以将 class 更简单地定义为 records。记录适用于 classes,其主要目的是透明且不可变地传递数据。

您可以使用 List.of 实例化不可修改的 List 对象。

与其为 time-of-day 发明自己的类型,不如使用 java.time.LocalTime

顺便说一句,火车号应该是字符串类型(或自定义class),而不是整数类型。车次实际上是车次标识符,不是数量也不是序数

此代码未经测试,用 iPhone 编写,因此可能需要一些编辑。

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

如果您需要一个可修改的列表,实例化ArrayList。但请注意,您可以将 List.of 生成的列表传递给其构造函数。这种技术使得 literals-style 语法简洁易读。

List< Person > persons = 
    new ArrayList <>(
        List.of(
            new Person( "Alice" ) , 
            new Person( "Bob" ) ,
            new Person( "Carol" ) 
        )
    )
;

你陷入了一个众所周知的 Java 陷阱:构造函数 Train(int,String,List<Stop>) 的参数 stop 不是 一个(一个实例) ArrayList,它只是 引用 此类实例。

这意味着语句

this.stop = stop;

在该构造函数中不保留 List 的实例,而只是一个引用。

因此,您应该注意到,当您省略对 stop.clear().

的调用时,所有列车的停靠站列表都将完全相同

您现在有两种选择来解决此问题:

  1. 不是在 stop 列表上调用 clear,而是通过调用 new ArrayList<Stop>.

    创建一个新实例
  2. 推荐的方法(因为第一种方法远非防弹……)如下所示:

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

以后如果想操作止损,也可以这样写

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

复制自