201621123061《Java程序设计》第八次学习总结

1. 本周学习总结

以你喜欢的方式(思维导图或其他)归纳总结集合相关内容。

2. 书面作业

1. ArrayList代码分析

1.1 解释ArrayList的contains源代码

源代码如下:

public boolean contains(Object o) {
        return indexOf(o) >= 0; 
    }

public int indexOf(Object o) {              
        if (o == null) {                    
            for (int i = 0; i < size; i++)   
                if (elementData[i]==null)    
                    return i;                
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

ArrayList的contains方法调用了indexOf方法。indexOf方法是通过对ArrayList型的对象的遍历,假如对象o找到和它相等的值,则放回该值的位置,否则返回-1。contains方法则是根据indexOf(o) >= 0是否成立来判断,若成立则返回true,即包含,不成立返回false,即不包含。

1.2 解释E remove(int index)源代码

源代码如下:

public E remove(int index) {
    rangeCheck(index);          //检查是否在范围内

    modCount++;                    //初始值为0
    E oldValue = elementData(index);     //保存旧数据

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);         //将移除位置之后所有的元素都向前挪动一个位置
    elementData[--size] = null;        //将最后一个元素置为空
    return oldValue;                      
}
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

首先判断要删除的位置是否超出的范围:如果超出,则抛出异常,否则删除该位置的元素,并且将移除位置之后所有的元素都向前挪动一个位置,将最后一个元素置为空。

1.3 结合1.1与1.2,回答ArrayList存储数据时需要考虑元素的具体类型吗?

不需要。ArrayLis存储是用Object[]数组实现的,Object是所有类的父类,所以不需要考虑元素的类型。

1.4 分析add源代码,回答当内部数组容量不够时,怎么办?

源代码如下:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);            // 确保下一个元素进来有空间
        elementData[size++] = e;
        return true;
    }

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // DEFAULT_CAPACITY = 10,默认长度为10
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);                       
    }

private void grow(int minCapacity) {                         //增加容量
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);  //增加原来容量的一半。
        if (newCapacity - minCapacity < 0)             //判断容量是否足够,够的话就直接以这个长度创建数组
            newCapacity = minCapacity;                       
        if (newCapacity - MAX_ARRAY_SIZE > 0)                //如果不够,再扩充
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//最后将原来的复制到新的数组中  
    }

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;                                   //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
    }

1.5 分析private void rangeCheck(int index)源代码,为什么该方法应该声明为private而不声明为public?

源代码如下:

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

rangeCheck方法用来判断是否超出容量范围,没有返回值,假如超出范围了就直接抛出异常。使用private是因为用户不需要知道rangeCheck方法是如何操作,因为在进行各个方法的调用时需要该方法时就会自动被调用,开发者不需要自己手动进行判断是否越界。

2. HashSet原理

2.1 将元素加入HashSet(散列集)中,其存储位置如何确定?需要调用那些方法?

首先要调用hashCode方法得到相应的哈希值,然后对哈希值进行计算,算出在哈希表中对应的位置。如果对应的位置上没有值,则将元素放在该位置上,如果该位置上有别的值,则调用equals方法比较位置上的值和要加入的元素的值,如果为true,则说明两个值相等,而HashSet不允许有重复的值,则用新元素代替就元素,如果结果为false,就通过散列冲突的解决办法解决。

2.2 将元素加入HashSet中的时间复杂度是多少?是O(n)吗?(n为HashSet中已有元素个数)

将元素加入HashSet中不需要遍历,时间复杂度为O(1)。

2.3 选做:尝试分析HashSet源代码后,重新解释2.1

源代码如下:

public boolean contains(Object o) {
    return map.containsKey(o);
}

public boolean containsKey(Object key) {    //如果此映射包含对于指定键(key)的映射关系,则返回true

    return getEntry(key) != null;  
} 
final Entry<K,V> getEntry(Object key) { //通过key获取value
    int hash = (key == null) ? 0 : hash(key.hashCode());//
    for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { 
        Object k;    
        if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))  
            return e;  
    }
    return null; 
}  

调用contains方法,contains又调用map.containsKey方法,该方法又调用getEntry方法来获取value。containsKey对返回的Keyvalue判断,如果为空在返回false,否则返回true。

3. ArrayListIntegerStack

题集jmu-Java-05-集合之ArrayListIntegerStack

3.1 比较自己写的ArrayListIntegerStack与自己在题集jmu-Java-04-面向对象2-进阶-多态、接口与内部类中的题目自定义接口ArrayIntegerStack,有什么不同?(不要出现大段代码)

  • ArrayListIntegerStack利用ArrayList实现栈的存储,ArrayList是长度可变化的数组,不必考虑栈满的情况。
  • ArrayIntegerStack利用长度不可变数组来实现栈的存储,说数组不可变,其实是因为一开始就要设定好数组的长度,需要考虑栈满的情况。

3.2 结合该题简单描述接口的好处,需以3.1为例详细说明,不可泛泛而谈。

接口对类的所有共性方法进行声明,实现这个接口的类再对方法进行重写。在3.1中,ArrayListIntegerStack和ArrayIntegerStack都有共同的方法,但是对这些方法的实现,对栈的存储方式不一样(重写的方法又不一样)。接口的方法在不同的类中实现,实现起来又能有不一样的功能,这样会比较方便,弥补了类不能被多继承的缺憾。

4. Stack and Queue

4.1 编写函数判断一个给定字符串是否是回文,一定要使用栈(请利用Java集合中已有的类),但不能使用java的Stack类(具体原因自己搜索)与数组。请粘贴你的代码,类名为Main你的学号。

4.2 题集jmu-Java-05-集合之银行业务队列简单模拟(只粘贴关键代码)。请务必使用Queue接口,并说明你使用了Queue接口的哪一个实现类?


使用了Queue接口的实现类Deque。

5. 统计文字中的单词数量并按单词的字母顺序排序后输出

题集jmu-Java-05-集合之5-2 统计文字中的单词数量并按单词的字母顺序排序后输出 (作业中不要出现大段代码)

5.1 实验总结


这题关键是要用TreeSet,可以自动排序。

3.码云及PTA

题目集:jmu-Java-05-集合

3.1. 码云代码提交记录

在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图

3.2 截图PTA题集完成情况图

需要有两张图(1. 排名图。2.PTA提交列表图)

3.3 统计本周完成的代码量

需要将每周的代码统计情况融合到一张表中。

周次 行数 新增行数 文件数 新增文件数
1 91 91 5 5
2 504 413 18 13
3 1092 588 28 10
5 1158 129 34 6
6 1539 381 40 6
7 2023 484 49 9
8 2477 454 57 8
9 2709 232 63 6

posted on 2017-11-10 23:18  球球滚吧hhh  阅读(148)  评论(1)    收藏  举报

导航