201521123122 《java程序设计》第七周学习总结

201521123122 《java程序设计》第七周实验总结


1. 本周学习总结

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


2. 书面作业

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;   
    }  

1.elementData 是"Object[]类型的数组",它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长
2.“null”的含义:在JVM规范中是这么说的:

,也就是说null是指一个不确定的对象,在java中,null对象不能使用equal函数,所以要区分是否为null。

3.代码的意思就是验证ArrayList中是否包含所查询的对象,如果存在,则返回其对象所在的位置,不存在的话,返回-1;

1.2 解释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;
}

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

1.rangeCheck函数的作用在于,如果想要删除的位置在size外面,则抛出一个IndexOutOfBoundsException的异常。
2.主要是把index这个位置的元素取出来,然后后面的元素位置依次向前进一位,然后最后一个元素设置为null;总体size减1;

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


应考虑是否为基本数据类型,除基本数据类型外的其他类型都可以存储。

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


同理,先贴代码:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // ensureCapacityInternal用来调整容量
    elementData[size++] = e;
    return true;
}  
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0) //如果超出容量,则调用grow方法增加容量
        grow(minCapacity);
}   
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); //增加原来容量的一半(右移一位就是/2),也就是说新List的容量是旧的1.5倍
    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); //把旧数组拷贝至新数组,这里说明了并不是增加原来数组的大小,而是引用了一个大小为原来数组1.5倍的新数组。
}  

从代码以及写的注释中可以看出,如果超出容量,会调用一个grow方法,引用一个新数组,其大小为原来数组的1.5倍,然后把旧数组拷贝至新数组。

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


rangeCheck代码在上面,我就不复制了。其根本原因还在于java的封装性,因为用户在用这个函数的时候,完全不用去考虑其内部结构,只需知道能否使用就可以了。


HashSet原理

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

1.set中不能存储相同的元素,所以要用equal()方法来保证元素的唯一性
2.从HashSet中访问元素时,HashSet先计算该元素的hashCode值,然后到该hashCode对应的位置取出该元素。所以要调用HashCode算法。

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


以下转自博客http://www.cnblogs.com/ITtangtang/p/3948538.html

对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,
源代码如下:

public class HashSet<E>  
   extends AbstractSet<E>  
   implements Set<E>, Cloneable, java.io.Serializable  
4{  
   static final long serialVersionUID = -5024744406713321676L;  
 
   // 底层使用HashMap来保存HashSet中所有元素。  
   private transient HashMap<E,Object> map;  
     
   // 定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。  
   private static final Object PRESENT = new Object();  
 
   /** 
    * 默认的无参构造器,构造一个空的HashSet。 
    *  
    * 实际底层会初始化一个空的HashMap,并使用默认初始容量为16和加载因子0.75。 
    */  
   public HashSet() {  
   map = new HashMap<E,Object>();  
   }  
 
   /** 
    * 构造一个包含指定collection中的元素的新set。 
    * 
    * 实际底层使用默认的加载因子0.75和足以包含指定 
    * collection中所有元素的初始容量来创建一个HashMap。 
    * @param c 其中的元素将存放在此set中的collection。 
    */  
   public HashSet(Collection<? extends E> c) {  
   map = new HashMap<E,Object>(Math.max((int) (c.size()/.75f) + 1, 16));  
   addAll(c);  
   }  
 
   /** 
    * 以指定的initialCapacity和loadFactor构造一个空的HashSet。 
    * 
    * 实际底层以相应的参数构造一个空的HashMap。 
    * @param initialCapacity 初始容量。 
    * @param loadFactor 加载因子。 
    */  
   public HashSet(int initialCapacity, float loadFactor) {  
   map = new HashMap<E,Object>(initialCapacity, loadFactor);  
   }  
 
   /** 
    * 以指定的initialCapacity构造一个空的HashSet。 
    * 
    * 实际底层以相应的参数及加载因子loadFactor为0.75构造一个空的HashMap。 
    * @param initialCapacity 初始容量。 
    */  
   public HashSet(int initialCapacity) {  
   map = new HashMap<E,Object>(initialCapacity);  
   }  
 
   /** 
    * 以指定的initialCapacity和loadFactor构造一个新的空链接哈希集合。 
    * 此构造函数为包访问权限,不对外公开,实际只是是对LinkedHashSet的支持。 
    * 
    * 实际底层会以指定的参数构造一个空LinkedHashMap实例来实现。 
    * @param initialCapacity 初始容量。 
    * @param loadFactor 加载因子。 
    * @param dummy 标记。 
    */  
   HashSet(int initialCapacity, float loadFactor, boolean dummy) {  
   map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);  
   }  
 
   /** 
    * 返回对此set中元素进行迭代的迭代器。返回元素的顺序并不是特定的。 
    *  
    * 底层实际调用底层HashMap的keySet来返回所有的key。 
    * 可见HashSet中的元素,只是存放在了底层HashMap的key上, 
    * value使用一个static final的Object对象标识。 
    * @return 对此set中元素进行迭代的Iterator。 
    */  
   public Iterator<E> iterator() {  
   return map.keySet().iterator();  
   }  
 
   /** 
    * 返回此set中的元素的数量(set的容量)。 
    * 
    * 底层实际调用HashMap的size()方法返回Entry的数量,就得到该Set中元素的个数。 
    * @return 此set中的元素的数量(set的容量)。 
    */  
   public int size() {  
   return map.size();  
   }  
 
   /** 
    * 如果此set不包含任何元素,则返回true。 
    * 
    * 底层实际调用HashMap的isEmpty()判断该HashSet是否为空。 
    * @return 如果此set不包含任何元素,则返回true。 
    */  
   public boolean isEmpty() {  
   return map.isEmpty();  
   }  
 
   /** 
    * 如果此set包含指定元素,则返回true。 
    * 更确切地讲,当且仅当此set包含一个满足(o==null ? e==null : o.equals(e)) 
    * 的e元素时,返回true。 
    * 
    * 底层实际调用HashMap的containsKey判断是否包含指定key。 
    * @param o 在此set中的存在已得到测试的元素。 
    * @return 如果此set包含指定元素,则返回true。 
    */  
   public boolean contains(Object o) {  
   return map.containsKey(o);  
   }  
 
   /** 
    * 如果此set中尚未包含指定元素,则添加指定元素。 
    * 更确切地讲,如果此 set 没有包含满足(e==null ? e2==null : e.equals(e2)) 
    * 的元素e2,则向此set 添加指定的元素e。 
    * 如果此set已包含该元素,则该调用不更改set并返回false。 
    * 
    * 底层实际将将该元素作为key放入HashMap。 
    * 由于HashMap的put()方法添加key-value对时,当新放入HashMap的Entry中key 
    * 与集合中原有Entry的key相同(hashCode()返回值相等,通过equals比较也返回true), 
    * 新添加的Entry的value会将覆盖原来Entry的value,但key不会有任何改变, 
    * 因此如果向HashSet中添加一个已经存在的元素时,新添加的集合元素将不会被放入HashMap中, 
    * 原来的元素也不会有任何改变,这也就满足了Set中元素不重复的特性。 
    * @param e 将添加到此set中的元素。 
    * @return 如果此set尚未包含指定元素,则返回true。 
    */  
   public boolean add(E e) {  
   return map.put(e, PRESENT)==null;  
   }  
 
   /** 
    * 如果指定元素存在于此set中,则将其移除。 
    * 更确切地讲,如果此set包含一个满足(o==null ? e==null : o.equals(e))的元素e, 
    * 则将其移除。如果此set已包含该元素,则返回true 
    * (或者:如果此set因调用而发生更改,则返回true)。(一旦调用返回,则此set不再包含该元素)。 
    * 
    * 底层实际调用HashMap的remove方法删除指定Entry。 
    * @param o 如果存在于此set中则需要将其移除的对象。 
    * @return 如果set包含指定元素,则返回true。 
    */  
   public boolean remove(Object o) {  
   return map.remove(o)==PRESENT;  
   }  
 
   /** 
    * 从此set中移除所有元素。此调用返回后,该set将为空。 
    * 
    * 底层实际调用HashMap的clear方法清空Entry中所有元素。 
    */  
   public void clear() {  
   map.clear();  
   }  
 
   /** 
    * 返回此HashSet实例的浅表副本:并没有复制这些元素本身。 
    * 
    * 底层实际调用HashMap的clone()方法,获取HashMap的浅表副本,并设置到  HashSet中。 
    */  
   public Object clone() {  
       try {  
           HashSet<E> newSet = (HashSet<E>) super.clone();  
           newSet.map = (HashMap<E, Object>) map.clone();  
           return newSet;  
       } catch (CloneNotSupportedException e) {  
           throw new InternalError();  
       }  
   }  
}

ArrayListIntegerStack

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

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

1.ArrayListIntegerStack是用ArrayList对象存储的,ArrayIntegerStack是用Integer存储的。
2.ArrayIntegerStack在出栈的时候需要移动top指针,ArrayListIntegerStack不需要top指针,调用ArrayList自有的remove()方法就可以。

3.2 简单描述接口的好处.

简单来说,就是可以通过一个接口来控制不同的类。

Stack and Queue

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

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

@SuppressWarnings("unused")
public class Main201521123122{
    public static void main(String[] args) {
        
        @SuppressWarnings("resource")
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入字符串");
        ArrayListStringStack Stack=new ArrayListStringStack();
        String n= sc.next();
        for(int i=0;i<n.length();i++)
        {
            Stack.push(String.valueOf(n.charAt(i)));
        }
        for(int j=0;j<n.length();j++){
            if(String.valueOf(n.charAt(j)).equals(Stack.pop())){
                System.out.println("是回文");
                break;
            }
            else {
                System.out.println("不是回文");
                break;
            }
                    
        }
    }
public class ArrayListStringStack implements StringStack {
    
    private ArrayList<String> list;
        
    public ArrayListStringStack() {
        list=new ArrayList<String>();
    }
    public String push(String item) {
        if(item==null)
            return null;
        list.add(item);
        return item;
    }
    
    @Override
    public String pop() {
        if(list.isEmpty())
            return null;
        return list.remove(list.size()-1);
    }
}
public interface StringStack {

    public String push(String item);
    public String pop();
}

4.2 题集jmu-Java-05-集合之5-6 银行业务队列简单模拟。(不要出现大段代码)

只需设置两个队列,然后奇数队列出两个,偶数队列出一个,知道其中一个为空,然后输出剩下的队列
代码如下:

 int n=in.nextInt();
     for( int i = 0; i < n; i++ ) {  
           int x=in.nextInt();  
           if( x % 2==0 )  qB.add( x );  
           else qA.add( x );  
       }  

偶数放在B窗口,奇数放在A窗口

while(!qA.isEmpty()||!qB.isEmpty()){
            Integer a1=qA.poll();
            if(a1!=null){
                if(qA.isEmpty()&&qB.isEmpty())
                    System.out.print(a1);
                else System.out.print(a1+" ");
            }
            Integer a2=qA.poll();
            if(a2!=null){
                if(qA.isEmpty()&&qB.isEmpty())
                    System.out.print(a2);
                else System.out.print(a2+" ");
            }
            Integer b=qB.poll();
            if(b!=null){
                if(qA.isEmpty()&&qB.isEmpty())
                    System.out.print(b);
                else System.out.print(b+" ");
            }
        }

输出两个A,在输出一个B

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

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

代码如下:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        Set<String>set=new TreeSet();
        Scanner in=new Scanner(System.in);
        while(in.hasNext()){
            String str=in.next();
            if(str.equals("!!!!!"))break;
            set.add(str);
        }
        System.out.println(set.size());
        if(set.size()<10)
            for (String string : set) {
                System.out.println(string);
                
            }
        else{
            for (int i = 0; i < 10; i++) {
                System.out.println(set.toArray()[i]);
                
            }
        }

    }
    

5.1 实验总结

用while(in.hasNext()),来拆分文章中的单词,而使用Treeset会自动将单词排好序,直接输出就可以。

3. 码云上代码提交记录及PTA实验总结

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

3.1. 码云代码提交记录

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

posted @ 2017-04-08 19:51  咸鱼阿明  阅读(181)  评论(0编辑  收藏  举报