ListIterator 在 start/End 处有不同的行为

ListIterator has different behaviour at start/End

我写了一个非常简单的获取程序,以更新我在 LinkedLists 上的技能,以备不时之需。 现在,我偶然发现了我没有预料到的行为。当我到达列表的 end/beginning 并转到 forward/Backward 时,相同的元素显示两次。

这是我认为它的工作方式:

List =   [<Pointer>E1, E2, E3]

在 next() 调用之后:

List =   [E1, <Pointer>E2, E3]

在 next() 调用之后:

List =   [E1, E2, <Pointer>E3]

在 previous() 调用之后:

List =   [E1, <Pointer>E2, E3]

但显然,我必须调用它两次才能使指针返回一次。为什么会这样,我该如何改变这种行为?

public class Playlist {

private LinkedList<Song> playList;
private ArrayList<Album> albums;
private Song currentSong;

Playlist() {
    this.playList = new LinkedList<>();
    this.albums = new ArrayList<>();
}

Playlist(ArrayList<Album> albums) {
    this.playList = new LinkedList<>();
    this.albums = albums;
}

void addAlbum(Album album) {
    albums.add(album);
}

void addSong(Song s) {
    if (albums.contains(s)) {
        playList.add(s);
    } else {
        System.err.println("Song unknown");
    }
}


public static void main(String[] args) {
    Song s1 = new Song("song1", 111);
    Song s2 = new Song("song2", 222);
    Song s3 = new Song("song3", 333);
    Song s4 = new Song("song4", 444);
    Song s5 = new Song("song5", 555);

    ArrayList<Song> songList1 = new ArrayList<>();
    songList1.add(s1);
    songList1.add(s2);
    songList1.add(s3);
    Album a1 = new Album(songList1);

    ArrayList<Song> songList2 = new ArrayList<>();
    songList2.add(s4);
    songList2.add(s5);
    Album a2 = new Album(songList2);

    Playlist p1 = new Playlist();
    p1.addAlbum(a1);
    p1.addAlbum(a2);
    for(Album a : p1.albums){
        for(Song s : a.getSongs()){
            p1.playList.add(s);
        }
    }

    ListIterator<Song> listIterator = p1.playList.listIterator();

    p1.currentSong = p1.playList.getFirst();
    Scanner scanner = new Scanner(System.in);
    p1.showMenu();
    String input = scanner.nextLine();
    ;

    while (!input.equals("q")) {
        switch (input) {
            case "s":
                if ((listIterator.hasNext())) {
                    p1.currentSong = listIterator.next();
                    System.out.println("Current song: " + p1.currentSong);
                } else {
                    System.out.println("End of playlist reached");
                }
                break;
            case "p":
                if (listIterator.hasPrevious()) {
                    p1.currentSong = listIterator.previous();
                } else {
                    System.out.println("Start of playlist reached");
                }
                break;
            default:
                System.out.println("Invalid input.");
                break;

        }
        p1.showMenu();
        input = scanner.nextLine();
    }
    System.out.println("Goodbye");
    scanner.close();
}

private void showMenu() {
    System.out.print("This is the menu.\n Your options: (s) - skip the current song.\n (p) - play previous song. \n (q) - Quit.\n +" +
            " Current Song playing: " + currentSong + "\n");
}

}

documentation 明确表示

Note that alternating calls to next and previous will return the same element repeatedly.

你一开始画的图(用教鞭)是对的,只是你可能理解错了。 next()方法returns指针右边的元素previous()方法returns在指针的左边

也许图片多加一个逗号:

会更好看
// list = [<Pointer>, E1, E2, E3] -- next=E1, previous=exception
assertEquals(E1, next());
// list = [E1, <Pointer>, E2, E3] -- next=E2, previous=E1
assertEquals(E2, next());
// list = [E1, E2, <Pointer>, E3] -- next=E3, previous=E2
assertEquals(E3, next());
// list = [E1, E2, E3, <Pointer>] -- next=exception, previous=E3
assertEquals(E3, previous());
// list = [E1, E2, <Pointer>, E3] -- next=E3, previous=E2
assertEquals(E2, previous());
// list = [E1, <Pointer>, E2, E3] -- next=E2, previous=E1
assertEquals(E1, previous());
// list = [<Pointer>, E1, E2, E3] -- next=E1, previous=exception

来自docs

A ListIterator has no current element; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next().

next()

Returns the next element in the list and advances the cursor position.

previous()

Returns the previous element in the list and moves the cursor position backwards.

您的插图与实际行为之间的区别在于光标位于 个元素之间,它不是指向元素的指针。

开始时,光标在列表开始之前。调用 next returns 第一个元素,并向前移动光标。现在光标位于第一个和第二个元素之间。现在调用 previous 将再次 return 第一个元素,因为那是光标之前的元素。