1. 本周学习总结
2. 书面作业
1.ArrayList代码分析
1.1 解释ArrayList的contains源代码
- 我们知道ArrayList是允许重复的,有序的元素的集合,但当我们想用它来放入不同的元素时,就可以使用contains()方法
- 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;
}
public boolean equals(Object obj) {
return (this == obj);
}
- 如果对象不为null,最终调用的是equals方法,进行比较。如果相同返回true,不同返回false。但是由于equals的局限性,对于新建两个对象,虽然代表同一个,但是由于虚拟机在开辟怕两个存储空间,所以也会被判断为是两个东西。所以一般都要重写equals方法。
1.2 解释E remove(int index)源代码
- remove(int)用于删除ArrayList数组容器中指定位置int上的元素(从0开始),并返回此元素.
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = elementData[index];
//numMoved需要移动的元素个数,也就是index后面的所有的元素个数
int numMoved = size - index - 1;
//将index后面的所有元素全部往前依次移动一个位置
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//经过arraycopy的移位,数组容器的最个位置被腾空,
//但是仍然持有某个对象的引用,需要把这个多余的引用置为null.
elementData[--size] = null; // Let gc do its work
return oldValue;
}
- 如果是remove((Integer)a)则是删除a这个元素,如图:
1.3 结合1.1与1.2,回答ArrayList存储数据时需要考虑元素的类型吗?
- 首先,ArrayList是一个数组列表,初始数组数据类型都为Object类型,而Object又是所有类的父类,也就是说数组内的原色可以是任意类型。
- 所以,任何类型的元素都是可以存储在ArrayList中的
1.4 分析add源代码,回答当内部数组容量不够时,怎么办?
- 会把当前容量的1.5倍值赋给新的容量
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//定义于ArrayList的父类AbstractList,用于存储结构修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//有些虚拟机会在数组内保留一些头部信息,尝试分配更大的容量可能会导致内存溢出
//容量扩容的精髓
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//当前容量的1.5倍赋值给新的容量
if (newCapacity - minCapacity < 0)//判断新容量是否足够,足够则使用当前新容量创建新数组,不够就将数组长度设置为需要的长度
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)//判断有没超过最大限制
newCapacity = hugeCapacity(minCapacity);
//将原来数组的值copy新数组中去, ArrayList的引用指向新数组(如果数据量很大还是建议初始化的时候指定容量的大小,提高效率)
elementData = Arrays.copyOf(elementData, newCapacity);
}
https://zhidao.baidu.com/question/135667727998224005.html
1.5 分析private void rangeCheck(int index)源代码,为什么该方法应该声明为private而不声明为public?
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- 使用private 声明,说明这个方法是用户无法获取到的,只能在代码内部自动进行。
- rangeCheck()方法被以下方法调用:
- get(int index)
- set(int index, E element)
- remove(int index)
- 这些方法在调用了
rangeCheck()
方法后,会马上调用elementData(int index)
方法来获取指定位置元素的值。这两个方法调用保证了0 < index < size(); - rangeCheck()方法保证index在ArrayList长度范围之内(index < size()),并在越界时抛出IndexOutOfBoundsException异常elementData()中的数组访问代码会在index < 0时抛出ArrayIndexOutOfBoundsException异常
作者:Han Yi
链接:https://www.zhihu.com/question/56689381/answer/150114817
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.HashSet原理
2.1 将元素加入HashSet(散列集)中,其存储位置如何确定?需要调用那些方法?
- HashSet类,是存在于java.util包中的类[1] 。同时也被称为集合,该容器中只能存储不重复的对象。
- 系统采用 Hash 算法决定集合元素的存储位置
implements Set<E>, Cloneable, java.io.Serializable
使用 HashMap 的 key 保存 HashSet 中所有元素- 初始化 HashSet,底层会初始化一个 HashMap
- 调用 HashMap 的 containsKey 判断是否包含指定 key
- equals() 方法,分别对各属性进行判断,是否相等
- hashCode() 方法,有可能两者并不相等,但是hash码相同,所以要结合起来比较
2.2 选做:尝试分析HashSet源代码后,重新解释1.1
- 当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的哈希码表,然后根据哈希吗找到相应的存储区域,最后取得该存储区域内的每个元素与该对象进行equals方法比较
- 所以hashmap需要重写hashCode和equals
- 但是对于list,就只要重写equals方法
3.ArrayListIntegerStack
题集jmu-Java-05-集合之5-1 ArrayListIntegerStack
3.1 比较自己写的ArrayListIntegerStack与自己在题集jmu-Java-04-面向对象2-进阶-多态、接口与内部类中的题目5-3自定义接口ArrayIntegerStack,有什么不同?(不要出现大段代码)
- 主要在于数组和动态数组的区别
class ArrayintegerStack implements IntegerStack{
private Integer[] arr;
}
class ArrayListIntegerStack implements IntegerStack{
ArrayList<Integer> list=new ArrayList<Integer>();
}
- ArrayList不用设定头指针,可以通过序号直接找到元素,进行删除,返回的操作
3.2 简单描述接口的好处.
- 方便让代码知道,需要实现哪些功能,这些功能也不止有这个类可以使用,其他类也可以用。
- 接口也是一种规范,同样的操作可以有不同的实现方式,但是最后都是要面向接口。就比如金牛的插座和西门子的插座,内部构造,原材料什么的有可能不同,但是对于用户来说,都是把插头插上就可以用了。
4.Stack and Queue
4.1 编写函数判断一个给定字符串是否是回文,一定要使用栈,但不能使用java的Stack类(具体原因自己搜索)。请粘贴你的代码,类名为Main你的学号。
package Test;
import java.util.ArrayList;
import java.util.Scanner;
interface IntegerStack{
public String push(String item);
public String pop();
public String peek();
public boolean empty();
public int size();
}
class ArrayListIntegerStack implements IntegerStack{
ArrayList<String> list=new ArrayList<String>();
@Override
public String push(String item) {
if(item==null)
return null;
list.add(item);
return item;
}
@Override
public String pop() {
if(!list.isEmpty()){
return list.remove(list.size()-1);
}
return null;
}
@Override
public String peek() {
if(list.size()==0)
return null;
else
return list.get(list.size()-1);
}
@Override
public boolean empty() {
if(list.size()==0)
return true;
else
return false;
}
@Override
public int size() {
return list.size();
}
@Override
public String toString() {
return list.toString();
}
}
public class Main201521123043{
public static void main(String[] arge){
ArrayListIntegerStack a=new ArrayListIntegerStack();
int i;
Scanner in=new Scanner(System.in);
String m=in.next();
Integer n = null;
for(i=0;i<m.length();i++)
a.push(String.valueOf(m.charAt(i)));
for(i=0;i<m.length();i++)
{
if(String.valueOf(m.charAt(i)).equals(a.pop()))
continue;
else{
System.out.println("false");
break;
}
}
if(i==m.length())
System.out.println("true");
}
}
4.2 题集jmu-Java-05-集合之5-6 银行业务队列简单模拟。(不要出现大段代码)
- 定义了两个队列,一个数组
Queue<Integer> qa = new LinkedList<Integer>();
Queue<Integer> qb = new LinkedList<Integer>();
Scanner input=new Scanner (System.in);
- 单数的加入队列qa,复数的加入队列qb
for(int i=1;i<size+1;i++)
{
num=Integer.parseInt(str[i]);
if(num%2==0) qb.offer(num);
else qa.offer(num);
}
for(int i=0;i<str.length-1;)
{
if(qa.size()!=0&&i<str.length-1) list[i++]=qa.poll();
if(qa.size()!=0&&i<str.length-1) list[i++]=qa.poll();
if(qb.size()!=0&&i<str.length-1) list[i++]=qb.poll();
}
for(int i=0;i<str.length-1;i++)
{
if(i!=str.length-2) System.out.printf("%d ",list[i]);
else System.out.printf("%d",list[i]);
}
5.统计文字中的单词数量并按单词的字母顺序排序后输出
题集jmu-Java-05-集合之5-2 统计文字中的单词数量并按单词的字母顺序排序后输出 (不要出现大段代码)
//按空格分开,加入到set里,重复的删除
while(in.hasNext())
{
a=in.next();
if(a.equals("!!!!!"))
break;
set.add(a);
//System.out.println(a);
}
```
//最后单词总数
System.out.println(set.size());
<p>
//利用二叉树排序排序
final TreeSet ts=new TreeSet(set);
ts.comparator();
<p>
//转换为数组输出
String[] str=(String[]) ts.toArray(new String[ts.size()]);
###5.1 实验总结
- Hashset本身没有排序方法,这里有两种方法,一种是把他保存在ArrayList里,再用Collections.sort()来排序
- 另一种就是使用二叉排序树
- 要把集合(List,Set)里的元素放入数组时,可以使用toArray(),方便逐个输出
##6.选做:加分考察-统计文字中的单词数量并按出现次数排序
>题集jmu-Java-05-集合之5-3 统计文字中的单词数量并按出现次数排序(不要出现大段代码)
###6.1 伪代码
- 输入同5-2,不变
- 相同的单词输入Map里
Map<String,Integer> coun =new TreeMap<String,Integer>();
if(set.contains(a))
{
if(coun.containsKey(a))
coun.put(a, coun.get(a)+1);
else
coun.put(a, 2);
}
set.add(a);
- 因为排序要求有变,所以通过collection比较器来实现排序
List<Map.Entry<String,Integer>> list = new ArrayList<Map.Entry<String,Integer>>(coun.entrySet());
Collections.sort(list,new Comparator<Map.Entry<String,Integer>>(){
@Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
return (o2.getValue() - o1.getValue());
}
});
###6.2 实验总结
- Map以按键/数值对的形式存储数据,和数组非常相似,在数组中存在的索引
- 关于怎么使用,一般是选择Map的子类,而不直接用Map类。如:HashMap,TreeMap ```Map<String,Integer> coun =new HashMap<String,Integer>();```
- remove(Object key) 从map中删除键和关联的值
- put(Object key,Object valus)将指定值与指定键相关联
![](http://images2015.cnblogs.com/blog/1109779/201704/1109779-20170407191208425-1160558043.jpg)
![](http://images2015.cnblogs.com/blog/1109779/201704/1109779-20170407191216050-2044717545.jpg)
##7.选做加分:面向对象设计大作业-改进
###7.1 完善图形界面(说明与上次作业相比增加与修改了些什么)
![](http://images2015.cnblogs.com/blog/1109779/201704/1109779-20170408205913660-1793297223.png)
- 增加了购物车界面,两个界面之间的转换正在完善
###7.2 使用集合类改进大作业
- 购物车列表使用的是list
#3. 码云上代码提交记录
![](http://images2015.cnblogs.com/blog/1109779/201704/1109779-20170408204418816-1187133334.jpg)