集合框架

ArrayList

集合与数组的区别:
如果要存放多个对象,可以使用数组,但是数组有局限性。
比如 声明长度是10的数组,不用的数组就浪费了,超过10的个数,又放不下。
集合关键字:
在这里插入图片描述

add用法

add 有两种用法
第一种是直接add对象,把对象加在最后面

 heros.add(new Hero("hero " + i));

第二种是在指定位置加对象

 heros.add(3, specialHero);

使用实例:

import java.util.ArrayList;
 import charactor.Hero;
 
public class TestCollection {
    public static void main(String[] args) {
        ArrayList heros = new ArrayList();
         // 把5个对象加入到ArrayList中
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero " + i));
        }
        System.out.println(heros);
         // 在指定位置增加对象
        Hero specialHero = new Hero("special hero");
        heros.add(3, specialHero);
         System.out.println(heros.toString());
     }
 }
contains 判断是否存在

通过方法contains 判断一个对象是否在容器中
判断标准: 是否是同一个对象,而不是name是否相同

get 获取指定位置的对象

通过get获取指定位置的对象,如果输入的下标越界,一样会报错。

import java.util.ArrayList;
 
import charactor.Hero;
 
public class TestCollection {
    public static void main(String[] args) {
        ArrayList heros = new ArrayList();
 
        // 初始化5个对象
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero " + i));
        }
        Hero specialHero = new Hero("special hero");
        heros.add(specialHero);
         
        //获取指定位置的对象
        System.out.println(heros.get(5));
        //如果超出了范围,依然会报错
        System.out.println(heros.get(6)); 
    }
}

得到的异常结果如下:
下标越界异常结果

IndexOf 获取对象所处的位置

indexOf用于判断一个对象在ArrayList中所处的位置
与contains一样,判断标准是对象是否相同,而非对象的name值是否相等

import java.util.ArrayList;
import charactor.Hero;
 
public class TestCollection {
    public static void main(String[] args) {
        ArrayList heros = new ArrayList();
         // 初始化5个对象
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero " + i));
        }
        Hero specialHero = new Hero("special hero");
        heros.add(specialHero);
        System.out.println(heros);
        System.out.println("specialHero所处的位置:"+heros.indexOf(specialHero));
        System.out.println("新的英雄,但是名字是\"hero 1\"所处的位置:"+heros.indexOf(new Hero("hero 1")));
     }
}

结果如下图:
获取两个不同的位置

remove 删除

remove可以根据下标删除ArrayList的元素

heros.remove(2);

也可以根据对象删除

 heros.remove(specialHero);
set 替换
//设置第五个位置的对象为hero 5
heros.set(5, new Hero("hero 5"));
size 获取大小

size 用于获取ArrayList的大小

heros.size()

toArray

toArray可以把一个ArrayList对象转换为数组。
需要注意的是,如果要转换为一个Hero数组,那么需要传递一个Hero数组类型的对象给toArray(),这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组

Hero hs[] = (Hero[])heros.toArray(new Hero[]{});
addAll把另一个容器所有对象都加进来
import java.util.ArrayList;
 import charactor.Hero;
 
public class TestCollection {
    public static void main(String[] args) {
        ArrayList heros = new ArrayList();
         // 初始化5个对象
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero " + i));
        }
         System.out.println("ArrayList heros:\t" + heros);
                  //把另一个容器里所有的元素,都加入到该容器里来
        ArrayList anotherHeros = new ArrayList();
        anotherHeros.add(new Hero("hero a"));
        anotherHeros.add(new Hero("hero b"));
        anotherHeros.add(new Hero("hero c"));
        System.out.println("anotherHeros heros:\t" + anotherHeros);
        heros.addAll(anotherHeros);
        System.out.println("把另一个ArrayList的元素都加入到当前ArrayList:");
        System.out.println("ArrayList heros:\t" + heros);
             }
}

效果如下图:
把所有的对象加入到另一个容器中

clear 清空
heros.clear();
练习题目

1、如果就是要判断集合里是否存在一个 name等于 "hero 1"的对象,应该怎么做?
在这里插入图片描述

import java.util.ArrayList;
import charactor.Hero;
 
public class TestCollection { 
    public static void main(String[] args) {
        ArrayList heros = new ArrayList();
        // 初始化5个对象
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero " + i));
        }
        Hero specialHero = new Hero("special hero");
        heros.add(specialHero);
        System.out.println(heros);
         
        /*方法一:转化为数组,再引用属性name来进行判断(不重写方法)*/
        Hero[] hs = (Hero[]) heros.toArray(new Hero[] {});
        for(Hero h:hs) {
            if(h.name.equals("hero 1")) {
                System.out.println("找到了name是hero 1的对象");
            }
        }
        
        /*方法二:Hero重写toString()方法为return name*/
        for(int i = 0;i<heros.size();i++) {
            if(heros.get(i).toString().equals("hero 1")) {
                System.out.println("找到了name是hero 1的对象");
            }
        }
    }
}
泛型

不指定泛型的容器,可以存放任何类型的元素
例如:List heros = new ArrayList();
指定了泛型的容器,只能存放指定类型的元素以及其子类
例如: List genericheros = new ArrayList();

import java.util.ArrayList;
import java.util.List;
import property.Item;
import charactor.APHero;
import charactor.Hero;
   
public class TestCollection {
      public static void main(String[] args) {          
        //对于不使用泛型的容器,可以往里面放英雄,也可以往里面放物品
        List heros = new ArrayList();          
        heros.add(new Hero("盖伦"));          
        //本来用于存放英雄的容器,现在也可以存放物品了
        heros.add(new Item("冰杖"));          
        //对象转型会出现问题
        Hero h1=  (Hero) heros.get(0);
        //尤其是在容器里放的对象太多的时候,就记不清楚哪个位置放的是哪种类型的对象了
        Hero h2=  (Hero) heros.get(1);      
        //引入泛型Generic
        //声明容器的时候,就指定了这种容器,只能放Hero,放其他的就会出错
        List<Hero> genericheros = new ArrayList<Hero>();
        genericheros.add(new Hero("盖伦"));
        //如果不是Hero类型,根本就放不进去
        //genericheros.add(new Item("冰杖"));
                 //除此之外,还能存放Hero的子类
        genericheros.add(new APHero());
                 //并且在取出数据的时候,不需要再进行转型了,因为里面肯定是放的Hero或者其子类
        Hero h = genericheros.get(0);
    		}
    }
泛型的简写

为了不使编译器出现警告,需要前后都使用泛型,像这样:
List genericheros = new ArrayList();
不过JDK7提供了一个可以略微减少代码量的泛型简写方式
List genericheros2 = new ArrayList<>();

泛型练习题

借助泛型和前面学习的面向对象的知识,设计一个ArrayList,使得这个ArrayList里,又可以放Hero,又可以放Item,但是除了这两种对象,其他的对象都不能放。
答案看 ArrayList中的泛型Generic。

集合框架的遍历

遍历
for循环遍历集合

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; 
import charactor.Hero;
 
public class TestCollection { 
    public static void main(String[] args) {
        List<Hero> heros = new ArrayList<Hero>(); 
        // 放5个Hero进入容器
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero name " + i));
        } 
        // 第一种遍历 for循环
        System.out.println("--------for 循环-------");
        for (int i = 0; i < heros.size(); i++) {
            Hero h = heros.get(i);
            System.out.println(h);
        } 
    } 
}

iterator迭代器遍历集合中的元素
迭代器

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; 
import charactor.Hero;
  
public class TestCollection { 
    public static void main(String[] args) {
        List<Hero> heros = new ArrayList<Hero>();
        //放5个Hero进入容器
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero name " +i));
        }         
        //第二种遍历,使用迭代器
        
        System.out.println("--------使用while的iterator-------");
        Iterator<Hero> it= heros.iterator();
        //从最开始的位置判断"下一个"位置是否有数据
        //如果有就通过next取出来,并且把指针向下移动
        //直到"下一个"位置没有数据
        while(it.hasNext()){
            Hero h = it.next();
            System.out.println(h);
        }
        
        //迭代器的for写法
        System.out.println("--------使用for的iterator-------");
        for (Iterator<Hero> iterator = heros.iterator(); iterator.hasNext();) {
            Hero hero = (Hero) iterator.next();
            System.out.println(hero);
        }         
    }    
}

增强型for循环
使用增强型for循环可以非常方便的遍历ArrayList中的元素,这是很多开发人员的首选。
不过增强型for循环也有不足:
无法用来进行ArrayList的初始化
无法得知当前是第几个元素了,当需要只打印单数元素的时候,就做不到了。 必须再自定下标变量。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import charactor.Hero;
 
public class TestCollection {
 
    public static void main(String[] args) {
        List<Hero> heros = new ArrayList<Hero>();
 
        // 放5个Hero进入容器
        for (int i = 0; i < 5; i++) {
            heros.add(new Hero("hero name " + i));
        }
 
        // 第三种,增强型for循环
        System.out.println("--------增强型for循环-------");
        for (Hero h : heros) {
            System.out.println(h);
        }
     }
}

其他集合

LinkedList

序列分先进先出FIFO,先进后出FILO
FIFO在Java中又叫Queue 队列
FILO在Java中又叫Stack 栈

与ArrayList一样,LinkedList也实现了List接口,诸如add,remove,contains等等方法。
除了实现了List接口外,LinkedList还实现了双向链表结构Deque,可以很方便的在头尾插入删除数据

双向链表-Deque

什么是链表结构: 与数组结构相比较,数组结构,就好像是电影院,每个位置都有标示,每个位置之间的间隔都是一样的。 而链表就相当于佛珠,每个珠子,只连接前一个和后一个,不用关心除此之外的其他佛珠在哪里。
addFirst在头部插入数据
addLast在尾部插入数据
getFirst查看头部数据
getLast查看尾部数据
removeFirst取出头部数据
removeLast取出尾部数据

队列-Dueue

LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。
Queue是先进先出队列 FIFO,常用方法:
----offer 在最后添加元素
----poll 取出第一个元素
----peek 查看第一个元素

效果图如下:
在这里插入图片描述

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
  
import charactor.Hero;
  
public class TestCollection {
  
    public static void main(String[] args) {
        //和ArrayList一样,LinkedList也实现了List接口
        List ll =new LinkedList<Hero>();
          
        //所不同的是LinkedList还实现了Deque,进而又实现了Queue这个接口
        //Queue代表FIFO 先进先出的队列
        Queue<Hero> q= new LinkedList<Hero>();
          
        //加在队列的最后面
        System.out.print("初始化队列:\t");
        q.offer(new Hero("Hero1"));
        q.offer(new Hero("Hero2"));
        q.offer(new Hero("Hero3"));
        q.offer(new Hero("Hero4"));
          
        System.out.println(q);
        System.out.print("把第一个元素取poll()出来:\t");
        //取出第一个Hero,FIFO 先进先出
        Hero h = q.poll();
        System.out.println(h);
        System.out.print("取出第一个元素之后的队列:\t");
        System.out.println(q);
          
        //把第一个拿出来看一看,但是不取出来
        h=q.peek();
        System.out.print("查看peek()第一个元素:\t");
        System.out.println(h);
        System.out.print("查看并不会导致第一个元素被取出来:\t");
        System.out.println(q);         
    }       
}
二叉树

二叉树排序-插入数据
假设通过二叉树对如下10个随机数进行排序
67,7,30,73,10,0,78,81,10,74
排序的第一个步骤是把数据插入到该二叉树中
插入基本逻辑是:小、相同的放左边,大的放右边

package collection;
  
public class Node {
    // 左子节点
    public Node leftNode;
    // 右子节点
    public Node rightNode;
      // 值
    public Object value;
      // 插入 数据
    public void add(Object v) {
        // 如果当前节点没有值,就把数据放在当前节点上
        if (null == value)
            value = v;
          // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
        else {
            // 新增的值,比当前值小或者相同
             
            if ((Integer) v -((Integer)value) <= 0) {
                if (null == leftNode)
                    leftNode = new Node();
                leftNode.add(v);
            }
            // 新增的值,比当前值大
            else {
                if (null == rightNode)
                    rightNode = new Node();
                rightNode.add(v);
            }
          }
    }
    public static void main(String[] args) { 
        int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
        Node roots = new Node();
        for (int number : randoms) {
            roots.add(number);
        }
     }
}
中序遍历

接上面的代码,在main方法的上面插入本代码

// 中序遍历所有的节点
    public List<Object> values() {
        List<Object> values = new ArrayList<>();
  
        // 左节点的遍历结果
        if (null != leftNode)
            values.addAll(leftNode.values());
  
        // 当前节点
        values.add(value);
  
        // 右节点的遍历结果
        if (null != rightNode)
  
            values.addAll(rightNode.values());
  
        return values;
    }
HashMap

HashMap储存数据的方式是—— 键值对
代码例子:

import java.util.HashMap;
   
public class TestCollection {
    public static void main(String[] args) {
        HashMap<String,String> dictionary = new HashMap<>();
        dictionary.put("adc", "物理英雄");
        dictionary.put("apc", "魔法英雄");
        dictionary.put("t", "坦克");                       
        System.out.println(dictionary.get("t"));
    }
}

元素不能重复

对于HashMap而言,key是唯一的,不可以重复的。
所以,以相同的key 把不同的value插入到 Map中会导致旧元素被覆盖,只留下最后插入的元素。
不过,同一个对象可以作为值插入到map中,只要对应的key不一样
---- object.put(“key”,value);

Hashset

Set中的元素,不能重复

import java.util.HashSet;
  
public class TestCollection {
    public static void main(String[] args) {
         
        HashSet<String> names = new HashSet<String>();
           names.add("gareen");
        System.out.println(names);
     //第二次插入同样的数据,是插不进去的,容器中只会保留一个
           names.add("gareen");
        System.out.println(names);
    }
}

没有顺序

Set中的元素,没有顺序。
严格的说,是没有按照元素的插入顺序排列

HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序。
换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。 所以在开发的时候,不能依赖于某种臆测的顺序,这个顺序本身是不稳定的。

遍历
Set不提供get()来获取指定位置的元素
所以遍历需要用到迭代器,或者增强型for循环

import java.util.HashSet;
import java.util.Iterator;
  
public class TestCollection {
    public static void main(String[] args) {
        HashSet<Integer> numbers = new HashSet<Integer>();
            for (int i = 0; i < 20; i++) {
            numbers.add(i);
        }
         
        //Set不提供get方法来获取指定位置的元素
        //numbers.get(0)
       
        //遍历Set可以采用迭代器iterator
        for (Iterator<Integer> iterator = numbers.iterator(); iterator.hasNext();) {
            Integer i = (Integer) iterator.next();
            System.out.println(i);
        }
                 //或者采用增强型for循环
        for (Integer i : numbers) {
            System.out.println(i);
        }
    }
}
Collection

Collection是 Set List Queue和 Deque的接口
Queue: 先进先出队列
Deque: 双向链表

注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
注:Deque 继承 Queue,间接的继承了 Collection

Collection

Collections

Collections是一个类,容器的工具类,就如同Arrays是数组的工具类
Collections类的关键字
Collections.reverse(对象名); 反转顺序
Collections.shuffle(对象名); 打乱混淆顺序
Collections.sort(对象名); 排序
Collections.swap(对象名,0,5); 交换顺序
Collections.rotate(对象名,2); 滚动顺序(集合内的元素向右移动2格)

ArrayList 和 HashSet的区别

有无顺序
ArrayList: 有顺序
HashSet: 无顺序

HashSet的具体顺序,既不是按照插入顺序,也不是按照hashcode的顺序。

能否重复
List中的数据可以重复
Set中的数据不能够重复

重复判断标准是:
首先看hashcode是否相同
如果hashcode不同,则认为是不同数据
如果hashcode相同,再比较equals,如果equals相同,则是相同数据,否则是不同数据

import java.util.ArrayList;
import java.util.HashSet;
    
public class TestCollection {
    public static void main(String[] args) {
           
        ArrayList<Integer> numberList =new ArrayList<Integer>();
        //List中的数据可以重复
        System.out.println("----------List----------");
        System.out.println("向List 中插入 9 9");
        numberList.add(9);
        numberList.add(9);
        System.out.println("List 中出现两个9:");
        System.out.println(numberList);
        System.out.println("----------Set----------");
        HashSet<Integer> numberSet =new HashSet<Integer>();
        System.out.println("向Set 中插入9 9");
        //Set中的数据不能重复
        numberSet.add(9);
        numberSet.add(9);
        System.out.println("Set 中只会保留一个9:");
        System.out.println(numberSet);
              }
}
ArrayList和LinkedList的区别

插入删除数据
ArrayList 插入,删除数据慢
LinkedList 插入,删除数据快

ArrayList是顺序结构,所以定位很快,指哪找哪。 就像电影院位置一样,有了电影票,一下就找到位置了。
LinkedList 是链表结构,就像手里的一串佛珠,要找出第99个佛珠,必须得一个一个的数过去,所以定位慢。

定位数据
ArrayList 定位数据速度更快,而LInkedLis速度则更慢

HashMap和Hashtable的区别

HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
区别1:
HashMap可以存放 null
Hashtable不能存放null
区别2:
HashMap不是线程安全的类
Hashtable是线程安全的类

HashMap<String,String> hashMap = new HashMap<String,String>();
         
        //HashMap可以用null作key,作value
        hashMap.put(null, "123");
        hashMap.put("123", null);
         
        Hashtable<String,String> hashtable = new Hashtable<String,String>();
        //Hashtable不能用null作key,不能用null作value
        hashtable.put(null, "123");
        hashtable.put("123", null);
几种set

HashSet — LinkedHashSet —TreeSet
HashSet: 无序
LinkedHashSet: 按照插入顺序
TreeSet: 从小到大排序

HashSet<Integer> numberSet1 =new HashSet<Integer>();
        //HashSet中的数据不是按照插入顺序存放
        numberSet1.add(88);
        numberSet1.add(8);
        numberSet1.add(888);
        System.out.println(numberSet1);
          
LinkedHashSet<Integer> numberSet2 =new LinkedHashSet<Integer>();
        //LinkedHashSet中的数据是按照插入顺序存放
        numberSet2.add(88);
        numberSet2.add(8);
        numberSet2.add(888);         
        System.out.println(numberSet2);
        
TreeSet<Integer> numberSet3 =new TreeSet<Integer>();
        //TreeSet 中的数据是进行了排序的
        numberSet3.add(88);
        numberSet3.add(8);
        numberSet3.add(888);
        System.out.println(numberSet3);

-----hashcode概念-----
所有的对象,都有一个对应的hashcode(散列值)

-----HashSet判断是否重复------
HashSet的数据是不能重复的,相同数据不能保存在一起,到底如何判断是否是重复的呢?
根据HashSet和HashMap的关系,我们了解到因为HashSet没有自身的实现,而是里面封装了一个HashMap,所以本质上就是判断HashMap的key是否重复。

比较器

Comparator
Comparable

使Hero类实现Comparable接口
在类里面提供比较算法
Collections.sort就有足够的信息进行排序了,也无需额外提供比较器Comparator
注: 如果返回-1, 就表示当前的更小,否则就是更大

聚合函数

JDK8之后,引入了对集合的聚合操作,可以非常容易的遍历,筛选,比较集中的元素。

public class TestAggregate {
  
    public static void main(String[] args) {
        Random r = new Random();
        List<Hero> heros = new ArrayList<Hero>();
        for (int i = 0; i < 10; i++) {
            heros.add(new Hero("hero " + i, r.nextInt(1000), r.nextInt(100)));
        }
         System.out.println("初始化集合后的数据 (最后一个数据重复):");
        System.out.println(heros);
                 //传统方式
        Collections.sort(heros,new Comparator<Hero>() {
            @Override
            public int compare(Hero o1, Hero o2) {
                return (int) (o2.hp-o1.hp);
            }
        });
                Hero hero = heros.get(2);
        System.out.println("通过传统方式找出来的hp第三高的英雄名称是:" + hero.name);
        //聚合方式
        String name =heros
            .stream()
            .sorted((h1,h2)->h1.hp>h2.hp?-1:1)
            .skip(2)
            .map(h->h.getName())
            .findFirst()
            .get();
         System.out.println("通过聚合操作找出来的hp第三高的英雄名称是:" + name);
             }
}

集合框架学习的深度好文

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值