谁能告诉我为什么这会返回一个空列表(NPE)?

发布于 2024-12-11 11:45:14 字数 2537 浏览 0 评论 0原文

我有这段代码,应该将 SortedLinkedList 的两个实例合并到一个 SLL 中(基于 mergeSort 合并),但返回一个空列表:

import java.util.LinkedList;

public class SortedLinkedList<T extends Comparable<? super T>>
    extends LinkedList<T> {

private LinkedList<T> list; // the sorted list

// constructor, sorted with insertion sort
public SortedLinkedList(LinkedList<T> in)
{
    if(in.peek() == null || in.size() == 1)
        return;
    else {
        list = new LinkedList<T>();
        for(T e : in)
            list.add(e);
        int i, j;
        T temp;
        for(i = 0; i < list.size(); i++){
            j = i;
            temp = list.get(j);
            while(j > 0 && list.get(j-1).compareTo(temp) > 0){
                list.set(j, list.get(j-1));
                j--;
            }
            list.set(j, temp);
        }
}
}

// return the union of the sorted linked lists this
// and other
public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    list = new LinkedList<T>();
    SortedLinkedList<T> temp = new SortedLinkedList<T>(list);
    int i = 0, j = 0;
    while(i < this.size() && j < other.size()){
        if(this.get(i).compareTo(other.get(j)) <= 0){
            temp.add(this.get(i));
            i++;
        }
        else {
            temp.add(other.get(j));
            j++;
        }
    }
    while(i < this.size()){
            temp.add(this.get(i));
            i++;
    }
    while(j < other.size()){
            temp.add(other.get(j));
            j++;
        }
    return temp;
}

// print the items in list
public void print()
{
    for(T e : list)
        System.out.println(e);
}
}

在 SLL 构造函数中,我让它简单地返回null list (私有变量 list 在此方法的第一行初始化)。然而,据我所知,这仍然应该给我一个 SLL 对象(最初也是 null)。我可以在方法本身中很好地添加到 temp ,但在打印列表时会出现 NullPointerException 。

我意识到将 get 与 LinkedList 一起使用并不是很有效。解决这个问题后我会用迭代器切换它们。

任何提示将不胜感激。

编辑:有趣的是,如果我将两个列表放入临时 LL 中,然后在其上使用构造函数,我会得到相同的结果。这些类型是兼容的,因为 SLL 扩展了 LL:

public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

EDIT2:看来 @Mead 是正确的...虽然 size() 和 get() 似乎适用于 SLL,但 add() 则不然。我想既然我扩展了 LinkedList,它也可以与 SLL 一起使用。它没有,并且覆盖它们也没有任何作用......我对此没有想法。建议?

I have this code that is supposed to merge two instances of SortedLinkedList into one SLL (based on mergeSort merge), but is returning an empty list instead:

import java.util.LinkedList;

public class SortedLinkedList<T extends Comparable<? super T>>
    extends LinkedList<T> {

private LinkedList<T> list; // the sorted list

// constructor, sorted with insertion sort
public SortedLinkedList(LinkedList<T> in)
{
    if(in.peek() == null || in.size() == 1)
        return;
    else {
        list = new LinkedList<T>();
        for(T e : in)
            list.add(e);
        int i, j;
        T temp;
        for(i = 0; i < list.size(); i++){
            j = i;
            temp = list.get(j);
            while(j > 0 && list.get(j-1).compareTo(temp) > 0){
                list.set(j, list.get(j-1));
                j--;
            }
            list.set(j, temp);
        }
}
}

// return the union of the sorted linked lists this
// and other
public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    list = new LinkedList<T>();
    SortedLinkedList<T> temp = new SortedLinkedList<T>(list);
    int i = 0, j = 0;
    while(i < this.size() && j < other.size()){
        if(this.get(i).compareTo(other.get(j)) <= 0){
            temp.add(this.get(i));
            i++;
        }
        else {
            temp.add(other.get(j));
            j++;
        }
    }
    while(i < this.size()){
            temp.add(this.get(i));
            i++;
    }
    while(j < other.size()){
            temp.add(other.get(j));
            j++;
        }
    return temp;
}

// print the items in list
public void print()
{
    for(T e : list)
        System.out.println(e);
}
}

In the SLL constructor, I have it simply return on a null list (and the private variable, list, is initialized in the first line of this method). However from what I know, this should still give me an SLL object (initially also null). I can add to temp just fine in the method itself, but get a NullPointerException when printing the list.

I realize it's not very efficient to use get with LinkedList. I'll switch them with an iterator after I settle this.

Any hints would be quite appreciated.

EDIT: Interestingly, I get the same result if I put both lists in a temporary LL and then use the constructor on it. The types are compatible since SLL extends LL:

public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

EDIT2: It seems @Mead was correct... while size() and get() seem to work for the SLL, add() does not. I was thinking that since I'm extending LinkedList, it would work with the SLL as well. It didn't, and overriding them did nothing as well... I'm out of ideas for this. Suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尾戒 2024-12-18 11:45:15

查看实现后只是好奇,但是您不能先执行 .addAll(...) ,然后执行 Collections.sort(...) 吗?这就是我个人所希望的。

just curious after looking at the implementation, but couldn't you have just done a .addAll(...) followed by a Collections.sort(...)? That's what I would have preferred personally.

(り薆情海 2024-12-18 11:45:14

伟大的!您的编辑几乎揭示了您的问题:您没有正确扩展 LinkedList。解决这个问题,然后致力于工会。

当前的问题:这是一个名为 SortedLinkedList 的类。我们可以假设它就像 LinkedList 一样,但其中的值是排序的。因此,考虑到这一点,这应该有效:

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinkedList<Integer>(unsorted);
System.out.println(sorted.size());
for (Integer i : sorted) {
   System.out.println(i);
}
// Should print out:
// 3
// 100
// 200
// 300

但它不会。运行你的代码,它会打印出什么?

后退?为什么打印出来是这样的?首先,考虑可以在类代码中使用的两个变量:this 引用 SortedLinkedList 对象,this.list 引用该 SortedLinkedList 对象内的实例变量。然后让我们看看构造函数:当您添加到列表时,您将调用 this.list.add()。您所编写的内容使 SortedLinkedList 成为 list 实例变量的包装器 - 您不是添加到 SortedLinkedList (this) 中,而是添加到其中的列表 (this.list)。
使用 this.list 实例变量的唯一方法是构造函数、print 和 makeUnion。所有其他 LinkedList 方法都不知道 list 变量,因此当我调用 get():

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinked<Integer>(unsorted);
System.out.println(sorted.get(0));

它不知道查看您的 this.list 变量,所以它不会打印 100 份。事实上,它会崩溃,因为索引 0 中没有值。您没有添加到 get() 实际使用的实例变量,因此该方法认为 SortedLinkedList 对象是空的。 this.list 是继承方法不知道的新变量。

因此,如果我们检查您的最新编辑:

public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

temp.addAll(this) 不起作用,因为 this 的所有方法都认为该列表为空,因为它们是不看 this.list。出于同样的原因,temp.addAll(other) 也不起作用。

扩展类时常见的情况是您希望现有方法继续工作。这意味着您需要将数据存储在 get() 和其他方法期望的位置。你是怎么做到的?好吧,你已经在这么做了! 您已经在做正确的事情 - 但您是在实例变量 this.list 而不是 this 上执行此操作。开始调用 this.add()this.set()this.size() 而不是 this.list.add () 并完全删除实例变量 list - 不需要,你有 this。然后数据将位于其他方法期望的位置。

(并在构造函数的第一行调用 super() ,因此调用超类构造函数中的代码)。祝你的作业好运 - 我建议在添加新方法之前测试对象的工作原理。

Great! Your edit pretty much reveals your problem: you're not extending the LinkedList properly. Fix that, and then work on union.

The problem at hand: This is a class called SortedLinkedList. We can assume it's meant to be just like LinkedList, but the values in it are sorted. So, given that, this should work:

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinkedList<Integer>(unsorted);
System.out.println(sorted.size());
for (Integer i : sorted) {
   System.out.println(i);
}
// Should print out:
// 3
// 100
// 200
// 300

But it will not. Run your code, what does it print out?

Back? Why did it print out that? First, consider two variables you can use in the class's code: this refers to the SortedLinkedList object, and this.list refers to an instance variable inside that SortedLinkedList object. Then let's look at the constructor: when you add to the list, you're calling this.list.add(). What you have written makes SortedLinkedList a wrapper around the list instance variable - you're not adding to the SortedLinkedList (this) you are adding to a list inside that (this.list).
The only methods that use your this.list instance variable are the constructor, print, and makeUnion. All the other LinkedList methods aren't aware of the list variable, so when I call get():

LinkedList<Integer> unsorted = new LinkedList<Integer>();
unsorted.add(200);
unsorted.add(100);
unsorted.add(300);
SortedLinkedList<Integer> sorted = new SortedLinked<Integer>(unsorted);
System.out.println(sorted.get(0));

It doesn't know to look in your this.list variable, so it won't get 100 to print. In fact, it will crash because there is no value in index 0. You didn't add to the instance variables that get() actually uses, so the methods think that SortedLinkedList object is empty. this.list is a new variable that the inheritted methods don't know about.

So, if we examine your latest edit:

public SortedLinkedList<T> makeUnion( SortedLinkedList<T> other)
{
    LinkedList<T> temp = new LinkedList<T>();
    temp.addAll(this);
    temp.addAll(other);
    SortedLinkedList<T> merge = new SortedLinkedList(temp);
    return merge;
}

temp.addAll(this) doesn't work, because all the methods of this think that the list is empty because they're not looking at this.list. temp.addAll(other) doesn't work either, for the same reason.

What is common when you extend classes is that you want the existing methods to continue working. This means that you need to store the data where get() and other methods expect it to be. How do you do that? Well, you're already doing it! You are already doing the right thing - but you are doing it on the instance variable this.list instead of this. Start calling this.add(), this.set(), this.size() instead of this.list.add() and remove the instance variable list completely - it's not needed, you have this. Then the data will be where the other methods expect it to be.

(And call super() on the first line of your constructor, so the code in the super class's constructor is called). Good luck on your homework - I'd recommend testing the object works as-is before adding new methods.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文