9 集合

collection接口

集合接口的继承关系:
—-| Collection 单列集合 的根接口
——-| List 如果是实现了List接口的集合类,该集合类具备的特点:有序,可重复。
——-| Set 如果是实现了Set接口的集合类,该集合类具备的特点: 无序,不可重复。

collection 接口方法

//增
add(E e);
addAll(Collection<? extends E> c);
//删
clear();
remove(Object o);
removeAll(Collection<?> c);
//交集
retainAll(Collection<?> c); 
//判断
contains(Object o);
containsAll (Collection<?> c);
equals(Object o);
isEmpty();
//迭代器
iteratior();
//大小
size();
//转换为数组
toArray();

collection 迭代器

  1. Collection—迭代的方法:

    toArray()
    iterator()

    迭代器的作用:就是用于抓取集合中的元素。
    迭代器的方法:

    hasNext()   问是否有元素可遍历。如果有元素可以遍历,返回true,否则返回false 。          
    next()    获取元素...
    remove()  移除迭代器最后一次返回 的元素。
    

    NoSuchElementException 没有元素的异常。
    出现的原因: 没有元素可以被迭代了。。。

List接口

  1. List接口中特有方法:

    添加
        add(int index, E element) 
        addAll(int index, Collection<? extends E> c) 
    获取:
        get(int index) 
        indexOf(Object o) 
        lastIndexOf(Object o) 
        subList(int fromIndex, int toIndex) 
    修改:
        set(int index, E element) 
    
    迭代
        listIterator() 
    
  2. List接口中特有的方法具备的特点: 操作的方法都存在索引值

    只有List接口下面的集合类才具备索引值。其他接口下面的集合类都没有索引值。

  3. listIterator()

    ListIterator特有的方法:

    hasPrevious()  判断是否存在上一个元素。
    previous()    当前指针先向上移动一个单位,然后再取出当前指针指向的元素。
    
    next();  先取出当前指针指向的元素,然后指针向下移动一个单位。
    
    add(E e)   把当前有元素插入到当前指针指向的位置上。
    set(E e)   替换迭代器最后一次返回的元素。
    
  4. 迭代器注意事项
    迭代器在变量元素的时候要注意事项: 在迭代器迭代元素的过程中,不允许使用集合对象改变集合中的元素个数,如果需要添加或者删除只能使用迭代器的方法进行操作

    如果使用过了集合对象改变集合中元素个数那么就会出现ConcurrentModificationException异常。

    迭代元素的过程中: 迭代器创建到使用结束的时间。
    错误案例:

            ListIterator it = list.listIterator();  //获取到迭代器
            list.add("aa");//改变元素个数,将会出现错误
            it.next();
            while(it.hasNext()){
                System.out.print(it.next()+",");
                list.add("aa");  // add方法是把元素添加到集合的末尾处的。

    正确使用:必须通过迭代器添加元素,因为迭代器指针会跳过通过迭代器添加的元素

            while(it.hasNext()){
                System.out.print(it.next()+",");
                it.add("aa"); // 把元素添加到当前指针指向位置
            }
            //最后集合元素的输出
            [张三, aa, 李四, aa, 王五, aa]

List接口的实现类

——| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
—————| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
—————| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
—————| Vector(了解即可) 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
——| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。

ArrayList

  1. List的实现类主要有三种:ArrayList LinkedList 和 Vector(不重要)

  2. ArrayList:

    ArrayList 底层是维护了一个Object数组实现的, 特点: 查询速度快,增删慢
    什么时候使用ArrayList: 如果目前的数据是查询比较多,增删比较少的时候,那么就使用ArrayList存储这批数据

    笔试题目: 使用ArrayList无参的构造函数创建一个对象时, 默认的容量是多少? 如果长度不够使用时又自增增长多少?
    ArrayList底层是维护了一个Object数组实现的,使用无参构造函数时,Object数组默认的容量是10,当长度不够时,自动增长0.5倍。

    特有的方法:

    ensureCapacity(int minCapaci上ty)//确保它至少能够容纳最小容量参数所指定的元素数
    trimToSize() 
    

LinkedList

  1. 特有方法:

        addFirst(E e) 
        addLast(E e) 
    
        getFirst() 
        getLast() 
    
        removeFirst() 
        removeLast()
    
  2. LinkedList实现数据结构

    1:栈 (1.6) : 主要是用于实现堆栈数据结构的存储方式。

        先进后出
        push() 
        pop()
    

    2:队列(双端队列1.5): 主要是为了让你们可以使用LinkedList模拟队列数据结构的存储方式。

        先进先出
        offer()
        poll()
    
  3. 返回逆序的迭代器对象
    descendingIterator() 返回逆序的迭代器对象

Vector

  1. 笔试题: 说出ArrayLsit与Vector的区别?
    相同点: ArrayList与Vector底层都是使用了Object数组实现的。

    不同点:
    1. ArrayList是线程不同步的,操作效率高。
    Vector是线程同步的,操作效率低。
    2. ArrayList是JDK1.2出现,Vector是jdk1.0的时候出现的。

Set接口

  1. Set接口是无序的
    无序: 添加元素 的顺序与元素出来的顺序是不一致的。
  2. 接口方法和collection 一致

Set接口的实现类

HashSet(依靠equals和HashCode的方法共同作用)

  1. 底层是使用了哈希表来支持的,特点: 存取速度快.
  2. 实现原理
    往Haset添加元素的时候,HashSet会先调用元素的hashCode方法得到元素的哈希值 ,然后通过元素的哈希值经过移位等运算,就可以算出该元素在哈希表中的存储位置。

    情况1: 如果算出元素存储的位置目前没有任何元素存储,那么该元素可以直接存储到该位置上。

    情况2: 如果算出该元素的存储位置目前已经存在有其他的元素了,那么会调用该元素的equals方法与该位置的元素再比较一次,如果equals返回的是true,那么该元素与这个位置上的元素就视为重复元素,不允许添加,如果equals方法返回的是false,那么该元素运行添加。

  3. HashSet注意事项
    HashSet是根据hashcode算出来的数值然后在哈希表中找相应的位置,如果某类是根据一个变量返回哈希值,如果修改了这个值,会影响remove的判断,如下

    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
    
    @Override
    public boolean equals(Object obj) {
        Book b  = (Book)obj;
        return this.name.equals(b.name);
    }
    public static void main(String[] args) {
        //不允许重复的书名存在。
        HashSet<Book> books = new HashSet<Book>();
        books.add(new Book("深入javaweb",34));
        books.add(new Book("java神书",78));
    
        //修改书名
        Iterator<Book> it = books.iterator();
        while(it.hasNext()){
            Book b = it.next();
            if(b.name.equals("java神书")){
                b.name = "java编程思想";
            }
        }
        //为什么修改名字之后不能删除了呢?
        books.remove(new Book("java神书",78));
        System.out.println("集合的元素:"+ books);
    }

TreeSet

  1. treeSet要注意的事项:

    1. 往TreeSet添加元素的时候,如果元素本身具备了自然顺序的特性,那么就按照元素自然顺序的特性进行排序存储。
    2. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么该元素所属的类必须要实现Comparable接口,把元素的比较规则定义在compareTo(T o)方法上。

    3. 如果比较元素的时候,compareTo方法返回的是0,那么该元素就被视为重复元素,不允许添加.(注意:TreeSet与HashCode、equals方法是没有任何关系。)

    4. 往TreeSet添加元素的时候, 如果元素本身没有具备自然顺序 的特性,而元素所属的类也没有实现Comparable接口,那么必须要在创建TreeSet的时候传入一个比较器。

    5. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而元素所属的类已经实现了Comparable接口, 在创建TreeSet对象的时候也传入了比较器, 那么是以比较器的比较规则优先使用

  2. 如何自定义定义比较器: 自定义一个类实现Comparator接口即可,把元素与元素之间的比较规则定义在compare方法内即可。

    自定义比较器的格式 :

        class  类名  implements Comparator{
    
        }
    

    推荐使用:使用比较器(Comparator)。

  3. TreeSet是可以对字符串进行排序 的, 因为字符串已经实现了Comparable接口。字符串的比较规则:

    情况一: 对应位置有不同的字符出现, 就比较的就是对应位置不同的字符。

    情况 二:对应位置上 的字符都一样,比较的就是字符串的长度。

set集合中的equals和hashCode (转)

  1. hashCode默认是计算出对象的内存地址,可以自己改写,例如String类就改写了
  2. Java 对equals方法和hashCode方法是这样规定的:
    1. 如果两个对象相同(使用equals比较,所以如果改写equals方法,一般也要改写hashCode方法),那么它们的hashCode值一定要相同;
    2. 如果两个对象的的hashCode相同,它们并不一定相同。(因为对于散列表来说每个位置是可能重复的)
  3. hashCode和equals的比较:
    equals的方法是给用户调用的,如果你想判断两个对象是否相等,你可以重写equals方法
    hashCode方法一般不会让用户调用,比如hashmap中,由于Key是不可以重复的(equals和hashCode只要有一个不等即使不重复),它在判断key是不是重复的时候就判断了hashcode方法,而且也用到了equals方法。

创建String对象过程的内存分配(转)

  1. String s = “abc”;
    在class文件被JVM装载到内存中,JVM会创建一块String Pool,当执行这句话时,JVM首先在Pool中查看是否存在相同的字符串(使用equals比较),如果存在该对象,则不用创建新的字符串,而直接使用String Pool中已存在的对象“abc,然后将引用s指向String Pool中创建的对象。

  2. String s = new String(“abc”);
    首先在Pool中查看是否存在对象”abc”, 没有则创建,然后又在Heap创建一个新的对象,并赋给s.

    如果Pool中存在,则不创建,然后在Heap中创建的对象.

    即New一个String对象 相当于创建了两个对象(常量池中一个 heap中一个)

注意:new 两个String对象,即使内容相同,内存地址也不相同

Tips

  1. 循环可以加标号
    outer: while(true)

    break outer;

  2. indexof 返回的是第一个

  3. 刚刚初始化的迭代器是不指向任何元素的
  4. Random random = new random();
    Random.nextint(大小) 这个范围不用减1,范围是0-大小

  5. 字符串转Int
    Integer.parseInt

小案例:使用LinkedList实现洗牌

package cn.itcast.list;
import java.util.LinkedList;
import java.util.Random;

/*
需求: 使用LinkedList存储一副扑克牌,然后实现洗牌功能。
*/
//扑克类
class Poker{
    String  color; //花色
    String num; //点数
    public Poker(String color, String num) {
        super();
        this.color = color;
        this.num = num;
    }
    @Override
    public String toString() {
        return "{"+color+num+"}";
    }
}
public class Demo2 {
    public static void main(String[] args) {
        LinkedList pokers = createPoker();
        shufflePoker(pokers);
        showPoker(pokers);
    }   
    //洗牌的功能
    public static void shufflePoker(LinkedList pokers){
        //创建随机数对象
        Random random = new Random();
        for(int i = 0 ; i <100; i++){ 
            //随机产生两个索引值
            int index1 = random.nextInt(pokers.size());
            int index2 = random.nextInt(pokers.size());
            //根据索引值取出两张牌,然后交换两张牌的顺序
            Poker poker1 = (Poker) pokers.get(index1);
            Poker poker2 = (Poker) pokers.get(index2);
            pokers.set(index1, poker2);
            pokers.set(index2, poker1);
        }   
    }
    //显示扑克牌
    public static void showPoker(LinkedList pokers){
        for(int i = 0 ; i<pokers.size() ; i++){
            System.out.print(pokers.get(i));
            //换行
            if(i%10==9){
                System.out.println();
            }
        }
    }
    //生成扑克牌的方法
    public static LinkedList createPoker(){
        //该集合用于存储扑克对象。
        LinkedList list = new LinkedList();     
        //定义数组存储所有的花色与点数
        String[] colors = {"黑桃","红桃","梅花","方块"};
        String[] nums = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
        for(int i = 0 ; i < nums.length ; i++){
            for(int j = 0 ; j<colors.length ; j++){
                list.add(new Poker(colors[j], nums[i]));
            }
        }
        return list;
    }   
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值