1. 本周学习总结
2. 书面作业
1. ArrayList代码分析
1.1 解释ArrayList的contains源代码
以下是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; }
可以看到,contains的源代码非常简单,返回indexOf(o) >= 0,调用了indexOf()方法;
我们先来了解一下indexOf()方法的实现:
- 返回第一次出现的指定元素的索引
- 在这个列表中,如果该列表不包含指定元素返回-1
- 如果指定元素为null,则遍历列表找出null的索引位置并返回
- 若指定元素不为null,同样遍历列表找出并返回指定元素的第一次索引位置
再来看contains方法的实现:
- 如果列表包含指定元素返回true,否则返回false
- 如果indexOf(o) >= 0则表明在列表中能找出指定元素o的索引位置
- 若indexOf(o)=-1则在列表中不存在指定元素,返回false
1.2 解释E remove(int index)源代码
以下是E remove(int index)源代码:
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
- 首先用rangeCheck(index)方法检查传进来的指标index是否越界,要知道rangeCheck方法无返回值,if(index>=size),抛出IndexOutOfBoundsException(outOfBoundsMsg(index));
- modCount++;这个列表的次数已经结构修改。结构修改是那些改变列表的大小,或扰乱它在这样一个时尚的迭代过程中可能产生不正确的结果。(这个姑且看看,不是很懂)
- numMoved的值表示被删除元素后面的元素个数
- 接着if后的代码作用是把指标后的元素按位往前挪一位,最后一个元素设为null
- 返回删除的元素
1.3 结合1.1与1.2,回答ArrayList存储数据时需要考虑元素的类型吗?
答案是不需要,可以通过以下例子来说明:
1.4 分析add源代码,回答当内部数组容量不够时,怎么办?
以下是add的源代码:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
有两种常用的add方式,一是直接在列表末尾添加新元素,二是在指定位置上插入新元素;
从以上代码可以看出,无论是哪种add方法,在ArrayList中都不存在内部数组容量不够的问题,因为add方法会使数组容量自动增加。1.5 分析private void rangeCheck(int index)源代码,为什么该方法应该声明为private而不声明为public?
封装思想,将具体的实现细节隐藏,而把功能作为整体提供给类的外部使用,用户不需要知道rangeCheck方法如何实现,只需要知道结果就行。
2. HashSet原理
2.1 将元素加入HashSet(散列集)中,其存储位置如何确定?需要调用那些方法?
先来看看HashSet的add方法如何实现:
public boolean add(E e) { return map.put(e, PRESENT)==null; }
public V put(K key, V value) { return putVal(hash(key), key, value, false, true);}
Set集中没有重复对象,如果添加Set集中的相同对象,则新对象覆盖原对象;
可以看出add方法调用了map.put()方法,put方法又调用了putVal方法,具体实现不管,但是可以看出调用了hash()函数,而hash函数可以帮助找到对象的索引位置。3. ArrayListIntegerStack
题集jmu-Java-05-集合之5-1 ArrayListIntegerStack
3.1 比较自己写的ArrayListIntegerStack与自己在题集jmu-Java-04-面向对象2-进阶-多态、接口与内部类中的题目5-3自定义接口ArrayIntegerStack,有什么不同?(不要出现大段代码)
首先相同之处是都实现了IntegerStack接口,继承了接口中的各种方法:
interface IntegerStack { public Integer push(Integer item); public Integer pop(); public Integer peek(); public boolean empty(); public int size();}
再者不同之处是ArrayListIntegerStack内部实现用ArrayList列表,ArrayIntegerStack内部实现用Array数组。
就光Array数组必须设置容量而ArrayList列表不需要来说,ArrayListIntegerStack就省事儿多了。 因为在重写各种方法时列表不需要考虑是否越界的问题,而数组需要多考虑这一问题。3.2 简单描述接口的好处.
- 接口实现扩展功能,让不同的类之间有了联系,却不相互干涉;
- 类可以实现多接口,接口中的方法可以不全部实现,体现接口的灵活性。
4. Stack and Queue
4.1 编写函数判断一个给定字符串是否是回文,一定要使用栈,但不能使用java的Stack类(具体原因自己搜索)。请粘贴你的代码,类名为Main你的学号。
import java.util.LinkedList;import java.util.Scanner;public class Main201521123007 { public static void main(String[] args) { Scanner in = new Scanner(System.in); String str = in.next(); String[] s = str.split(""); LinkedListstack = new LinkedList (); for (String string : s) { stack.add(string); } int i = 0; for (; i < s.length / 2; i++) { if (stack.pollLast().equals(s[i])) { continue; } else { System.out.println(str + "不是回文"); break; } } if (i == s.length / 2) System.out.println(str + "是回文"); in.close(); }}
4.2 题集jmu-Java-05-集合之5-6 银行业务队列简单模拟。(不要出现大段代码)
Queueq1=new ArrayDeque (); Queue q2=new ArrayDeque (); for (int i = 0; i < n; i++) { if(q1.size()==2){//A窗口奇编号,2倍速 System.out.printf(q1.poll()+" "+q1.poll()+" ");//A窗口输出 if(q2.size()>=1)//B窗口偶编号,单倍速 System.out.printf(q2.poll()+" ");//B窗口输出 } if(No[i]%2==1) q1.add(No[i]);//奇编号加入q1队列 else q2.add(No[i]);//偶编号加入q2队列 } while(q1.size()>1) System.out.printf(q1.poll()+" "); if(q1.size()==1)//控制输出最后不含空格 System.out.printf(q1.poll()+""); while(q2.size()>1) System.out.printf(q2.poll()+" "); if(q2.size()==1)//控制输出最后不含空格 System.out.printf(q2.poll()+"");
5. 统计文字中的单词数量并按单词的字母顺序排序后输出
题集jmu-Java-05-集合之5-2 统计文字中的单词数量并按单词的字母顺序排序后输出 (不要出现大段代码)
public static void main(String[] args) { SetstrSet = new TreeSet ();//TreeSet本身实现有序 Scanner in = new Scanner(System.in); int m = 10; while (in.hasNext()) { String str = in.next(); if(str.equals("!!!!!"))//结束输入 break; else if (!strSet.contains(str)) strSet.add(str);//添加到strSet } System.out.println(strSet.size());//打印strSet大小,即文字中的单词数量 if (strSet.size() <= 10)//打印格式,单词数小于等于10,全部打印 for (String s : strSet) { System.out.println(s); } else//单词数大于10,按单词的字母顺序排序后输出前十 for (String s : strSet) { if (m-- <= 0) break; System.out.println(s); } in.close(); }
5.1 实验总结
- Set集不含重复对象
- Set无序,但实现类TreeSet按特定方式排序
6. 选做:加分考察-统计文字中的单词数量并按出现次数排序
题集jmu-Java-05-集合之5-3 统计文字中的单词数量并按出现次数排序(不要出现大段代码)
6.1 伪代码
Mapcm = new TreeMap ();//因为键对象不可重复,值对象可重复,让单词对应键String,除此案次数对应值Integer while (in.hasNext()) { String str = in.next(); if (str.equals("!!!!!"))//结束输入 break; else if (!cm.containsKey(str))//判断键对象是否存在 cm.put(str, 1);//新键值对 else {//已存在键对象 int n = (int) cm.get(str);// 获取v值 cm.put(str, n + 1);//v值+1,存入TreeMap } }
List> arrayList = new ArrayList >(cm.entrySet());//创建一个列表接收键值对 Collections.sort(arrayList, new Comparator >() {//匿名内部类,比较 public int compare(Map.Entry o1, Map.Entry o2) { return ((Integer) o2.getValue()) - ((Integer) o1.getValue()); } });
int n=10; for (Map.Entryentry : arrayList) {//控制输出 if(n--==0) break; String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + "=" + value); }
6.2 实验总结
- 用Map的put(k,v)方法向集合中加入新元素
- 用get方法检索键对象映射的值对象
- TreeMap是按键对象排序的,如果要按值对象排序则要写一个比较方法
7. 面向对象设计大作业-改进
7.1 完善图形界面(说明与上次作业相比增加与修改了些什么)
7.2 使用集合类改进大作业
LinkedListlist; public Shopcart Add(Product goods,double sum){ Shopcart sc=new Shopcart(goods); sc.sum=sum; list.add(sc); return sc; }