CS61B HW1: 构建ArrayRingBuffer数据结构时java.lang.ArrayStoreException: java.lang.Double报错信息的处理

1、问题背景

在完成UC Berkeley的CS61B课程HW1的过程中,要求我们完成一个电子合成器的包,用来模拟吉他乐声,其中的一步是构建一个ArrayRingBuffer的数据结构,用其来实现Karplus-Strong算法,这个数据结构继承了一个名为AbstractBoundedQueue的抽象类,而这个抽象类实现了一个名为BoundedQueue的接口类,这个数据结构有基本的环形数组的特征,同时包含了生成迭代器,我首次实现的代码如下

import java.util.Iterator;
import java.util.NoSuchElementException;

// BoundedQueue (Interface)
public interface BoundedQueue<T> extends Iterable<T> {
    int capacity();     // return size of the buffer
    int fillCount();    // return number of items currently in the buffer
    void enqueue(T x);  // add item x to the end
    T dequeue();        // delete and return item from the front
    T peek();           // return (but do not delete) item from the front

    /** Is the buffer empty (fillCount equals zero)? */
    default boolean isEmpty() {
        return fillCount() == 0;
    }

    /** Is the buffer full (fillCount is same as capacity)? */
    default boolean isFull() {
        return capacity() == fillCount();
    }

}

// AbstractBoundedQueue (Abstract class)
public abstract class AbstractBoundedQueue<T> implements BoundedQueue<T> {

    protected int fillCount;
    protected int capacity;

    @Override
    public int capacity() {
        return capacity;
    }

    @Override
    public int fillCount() {
        return fillCount;
    }

}

// ArrayRingBuffer
public class ArrayRingBuffer<T> extends AbstractBoundedQueue<T> {
    /* Index for the next dequeue or peek. */
    private int first;            // index for the next dequeue or peek
    /* Index for the next enqueue. */
    private int last;
    /* Array for storing the buffer data. */
    private T[] rb;

    /**
     * Create a new ArrayRingBuffer with the given capacity.
     */
    public ArrayRingBuffer(int capacity) {

        this.capacity = capacity;
        this.fillCount = 0;
        first = 0;
        last = 0;
        rb = (T[]) new Objects[capacity];
    }

    private int addOne(int index) {
        return (index + 1) % capacity;
    }

    /**
     * Adds x to the end of the ring buffer. If there is no room, then
     * throw new RuntimeException("Ring buffer overflow"). Exceptions
     * covered Monday.
     */
    @Override
    public void enqueue(T x) {
        if (isFull()) {
            throw new RuntimeException("Ring buffer overflow");
        }
        rb[last] = x;
        last = addOne(last);
        this.fillCount++;
    }

    /**
     * Dequeue the oldest item in the ring buffer. If the buffer is empty, then
     * throw new RuntimeException("Ring buffer underflow"). Exceptions
     * covered Monday.
     */
    @Override
    public T dequeue() {
        if (isEmpty()) {
            throw new RuntimeException("Ring buffer underflow");
        }
        T res = rb[first];
        fillCount--;
        first = addOne(first);
        return res;
    }

    /**
     * Return oldest item, but don't remove it.
     */
    public T peek() {
        if (fillCount == 0) {
            throw new RuntimeException("The ArrayRingBuffer is EMPTY!");
        }
        return rb[first];
    }


    private class BufferIterator implements Iterator<T> {

        private int index;
        private int curNum;
        public BufferIterator() {
            index = first;
            curNum = 0;
        }
        @Override
        public boolean hasNext() {
            return curNum < fillCount;
        }

        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            T nextValue = rb[index];
            curNum++;
            index = addOne(index);
            return nextValue;
        }
    }

    @Override
    public Iterator<T> iterator() {
        return new BufferIterator();
    }

}

2、问题发现

IDEA未提示错误,可以正常编译,但是始终无法通过单元测试,报错信息为java.lang.ArrayStoreException: java.lang.Double,是Java中的一个运行时异常,表示尝试将一个对象存储到数组中,但对象的类型与数组的元素类型不兼容。我开始以为是我传入的数据类型有问题,但是上下检查没有问题,很清楚的是double类型,在泛型的声明也没有混淆Double和double,经过debug检查,最后将问题锁定在了ArrayRingBuffer的构造函数中,如下所示

public ArrayRingBuffer(int capacity) {

        this.capacity = capacity;
        this.fillCount = 0;
        first = 0;
        last = 0;
        rb = (T[]) new Objects[capacity];
    }

3、问题解决

因为类似的数据结构我此前写过,所以写的比较得心应手,也使用了很多的自动补全,没有仔细检查,看了很久才发现在给rb变量绑定数组对象的时候,new的是Objects[]而不是Ojbect[],我很惊讶代码自动补全的结果是这样,在修改之后发现可以通过测试了,问题解决

4、回顾

通过查阅资料,我发现Java中存在Object和Objects两个类,其中Object的意思耳熟能详不用多说,Objects的全名是java.util.Objects,它提供了静态方法来操作对象,例如检查是否为 null、比较对象等,一般不用于构建数组,因为它们限制了数组元素的类型。

5、完整代码

下面附上经过修改的完整代码

import java.util.Iterator;
import java.util.NoSuchElementException;

// BoundedQueue (Interface)
public interface BoundedQueue<T> extends Iterable<T> {
    int capacity();     // return size of the buffer
    int fillCount();    // return number of items currently in the buffer
    void enqueue(T x);  // add item x to the end
    T dequeue();        // delete and return item from the front
    T peek();           // return (but do not delete) item from the front

    /** Is the buffer empty (fillCount equals zero)? */
    default boolean isEmpty() {
        return fillCount() == 0;
    }

    /** Is the buffer full (fillCount is same as capacity)? */
    default boolean isFull() {
        return capacity() == fillCount();
    }

}

// AbstractBoundedQueue (Abstract class)
public abstract class AbstractBoundedQueue<T> implements BoundedQueue<T> {

    protected int fillCount;
    protected int capacity;

    @Override
    public int capacity() {
        return capacity;
    }

    @Override
    public int fillCount() {
        return fillCount;
    }

}

// ArrayRingBuffer
public class ArrayRingBuffer<T> extends AbstractBoundedQueue<T> {
    /* Index for the next dequeue or peek. */
    private int first;            // index for the next dequeue or peek
    /* Index for the next enqueue. */
    private int last;
    /* Array for storing the buffer data. */
    private T[] rb;

    /**
     * Create a new ArrayRingBuffer with the given capacity.
     */
    public ArrayRingBuffer(int capacity) {

        this.capacity = capacity;
        this.fillCount = 0;
        first = 0;
        last = 0;
        rb = (T[]) new Object[capacity];
    }

    private int addOne(int index) {
        return (index + 1) % capacity;
    }

    /**
     * Adds x to the end of the ring buffer. If there is no room, then
     * throw new RuntimeException("Ring buffer overflow"). Exceptions
     * covered Monday.
     */
    @Override
    public void enqueue(T x) {
        if (isFull()) {
            throw new RuntimeException("Ring buffer overflow");
        }
        rb[last] = x;
        last = addOne(last);
        this.fillCount++;
    }

    /**
     * Dequeue the oldest item in the ring buffer. If the buffer is empty, then
     * throw new RuntimeException("Ring buffer underflow"). Exceptions
     * covered Monday.
     */
    @Override
    public T dequeue() {
        if (isEmpty()) {
            throw new RuntimeException("Ring buffer underflow");
        }
        T res = rb[first];
        fillCount--;
        first = addOne(first);
        return res;
    }

    /**
     * Return oldest item, but don't remove it.
     */
    public T peek() {
        if (fillCount == 0) {
            throw new RuntimeException("The ArrayRingBuffer is EMPTY!");
        }
        return rb[first];
    }


    private class BufferIterator implements Iterator<T> {

        private int index;
        private int curNum;
        public BufferIterator() {
            index = first;
            curNum = 0;
        }
        @Override
        public boolean hasNext() {
            return curNum < fillCount;
        }

        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            T nextValue = rb[index];
            curNum++;
            index = addOne(index);
            return nextValue;
        }
    }

    @Override
    public Iterator<T> iterator() {
        return new BufferIterator();
    }

}

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值