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)
posted on 2017-04-04 13:49  谷LL  阅读(222)  评论(0编辑  收藏  举报