zoukankan      html  css  js  c++  java
  • Java集合框架与泛型

    ArrayList

    与数组的区别

    • 使用数组的局限性
      如果要存放多个对象,可以使用数组,但是数组有局限性
      比如 声明长度是10的数组
      不用的数组就浪费了,超过10的个数,又放不下
    package charactor;
     
    public class Hero {
        public String name;
        public float hp;
     
        public int damage;
     
        public Hero() {
     
        }
     
        // 增加一个初始化name的构造方法
        public Hero(String name) {
     
            this.name = name;
        }
     
        // 重写toString方法
        public String toString() {
            return name;
        }
    }
    
    package collection;
     
    import charactor.Hero;
     
    public class TestCollection {
        public static void main(String[] args) {
            //数组的局限性
            Hero heros[] = new Hero[10];
            //声明长度是10的数组
            //不用的数组就浪费了
            //超过10的个数,又放不下
            heros[0] = new Hero("盖伦");
                    //放不下要报错
            heros[20] = new Hero("提莫"); 
        }  
    }
    
    • ArrayList存放对象
      为了解决数组的局限性,引入容器类的概念。
      最常见的容器类就是ArrayList,容器的容量会随着对象的增加自动增长
      只需要不断往容器里增加英雄即可,不用担心会出现数组的边界问题。
    package collection;
     
    import java.util.ArrayList;
    import charactor.Hero;
     
    public class TestCollection {
        @SuppressWarnings("rawtypes")
        public static void main(String[] args) {
            //容器类ArrayList,用于存放对象
            ArrayList heros = new ArrayList();
            heros.add( new Hero("盖伦"));
            System.out.println(heros.size());
             
            //容器的容量"capacity"会随着对象的增加,自动增长
            //只需要不断往容器里增加英雄即可,不用担心会出现数组的边界问题。
            heros.add( new Hero("提莫"));
            System.out.println(heros.size());  
        } 
    }
    

    常用方法

    • 增加
      add 有两种用法
      第一种是直接add对象,把对象加在最后面
      heros.add(new Hero("hero " + i));
      第二种是在指定位置加对象
      heros.add(3, specialHero);
    package collection;
     
    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 判断一个对象是否在容器中
      判断标准: 是否是同一个对象,而不是name是否相同
    package collection;
     
    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是否相同
            System.out.print("虽然一个新的对象名字也叫 hero 1,但是contains的返回是:");
            System.out.println(heros.contains(new Hero("hero 1")));
            System.out.print("而对specialHero的判断,contains的返回是:");
            System.out.println(heros.contains(specialHero));
        }
    }
    

    • 获取指定位置的对象
      通过 get 获取指定位置的对象,如果输入的下标越界,一样会报错
    package collection;
     
    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用于判断一个对象在ArrayList中所处的位置
      与contains一样,判断标准是对象是否相同,而非对象的name值是否相等
    package collection;
     
    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用于把对象从ArrayList中删除
      remove可以根据下标删除ArrayList的元素
      heros.remove(2);
      也可以根据对象删除
      heros.remove(specialHero);
    package collection;
     
    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);
            heros.remove(2);
            System.out.println("删除下标是2的对象");
            System.out.println(heros);
            System.out.println("删除special hero");
            heros.remove(specialHero);
            System.out.println(heros);         
        }
    }
    

    • 替换
      set用于替换指定位置的元素
    package collection;
     
    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("把下标是5的元素,替换为"hero 5"");
            heros.set(5, new Hero("hero 5"));
            System.out.println(heros);
        }
    }
    

    • 获取大小
      size 用于获取ArrayList的大小
    package collection;
     
    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("获取ArrayList的大小:");
            System.out.println(heros.size());
        }
    }
    

    • 转换为数组
      toArray可以把一个ArrayList对象转换为数组。
      需要注意的是,如果要转换为一个Hero数组,那么需要传递一个Hero数组类型的对象给toArray(),这样toArray方法才知道,你希望转换为哪种类型的数组,否则只能转换为Object数组
    package collection;
     
    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);
            Hero hs[] = (Hero[])heros.toArray(new Hero[]{});
            System.out.println("数组:" +hs);
        }
    }
    

    • 把另一个容器所有对象都加进来
      addAll 把另一个容器所有对象都加进来
    package collection;
     
    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:	" + 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:	" + anotherHeros);
            heros.addAll(anotherHeros);
            System.out.println("把另一个ArrayList的元素都加入到当前ArrayList:");
            System.out.println("ArrayList heros:	" + heros);   
        }
    }
    

    • 清空
      clear 清空一个ArrayList
    package collection;
     
    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:	" + heros);
            System.out.println("使用clear清空");
            heros.clear();
            System.out.println("ArrayList heros:	" + heros);
        }
    }
    

    List接口

    • ArrayList 和 List
      ArrayList实现了接口List
      常见的写法会把引用声明为接口List类型
      注意:是java.util.List,而不是java.awt.List
    package collection;
      
    import java.util.ArrayList;
    import java.util.List;
    import charactor.Hero;
      
    public class TestCollection {
        public static void main(String[] args) {
            //ArrayList实现了接口List
             
            //常见的写法会把引用声明为接口List类型
            //注意:是java.util.List,而不是java.awt.List
            //接口引用指向子类对象(多态)
             
            List heros = new ArrayList();
            heros.add( new Hero("盖伦"));
            System.out.println(heros.size());
        } 
    }
    
    • List接口的方法
      因为ArrayList实现了List接口,所以List接口的方法ArrayList都实现了。

    泛型

    • 泛型 Generic
      不指定泛型的容器,可以存放任何类型的元素
      指定了泛型的容器,只能存放指定类型的元素以及其子类
    package property;
     
    public class Item {
        String name;
        int price;
         
        public Item(){
             
        }
         
        //提供一个初始化name的构造方法
        public Item(String name){
            this.name = name;
        }
         
        public void effect(){
            System.out.println("物品使用后,可以有效果");
        }  
    }
    
    package collection;
       
    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<Hero> genericheros = new ArrayList<Hero>();
      不过JDK7提供了一个可以略微减少代码量的泛型简写方式
      List<Hero> genericheros2 = new ArrayList<>();
    package collection;
       
    import java.util.ArrayList;
    import java.util.List; 
    import charactor.Hero;
       
    public class TestCollection {  
        public static void main(String[] args) {
            List<Hero> genericheros = new ArrayList<Hero>();
            List<Hero> genericheros2 = new ArrayList<>();      
        }       
    }
    

    遍历

    • 用for循环遍历
    package collection;
     
    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); //获得第i个英雄对象
                System.out.println(h);
            } 
        }
    }
    
    • 迭代器遍历
      迭代器有一个空的头部,直接hasNext的就是第一个
    package collection;
     
    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循环也有不足:
      1.无法用来进行ArrayList的初始化
      2.无法得知当前是第几个元素了,当需要只打印单数元素的时候,就做不到了,必须再自定下标变量。
    package collection;
     
    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

    • LinkedList 与 List接口
      与ArrayList一样,LinkedList也实现了List接口,诸如add,remove,contains等等方法,在此不作赘述,接下来要讲的是LinkedList的一些特别的地方
    • 双向链表 - Deque
      除了实现了List接口外,LinkedList还实现了双向链表结构Deque,可以很方便的在头尾插入删除
      数据什么是链表结构:与数组结构相比较,数组结构,就好像是电影院,每个位置都有标示,每个位置之间的间隔都是一样的。 而链表就相当于佛珠,每个珠子,只连接前一个和后一个,不用关心除此之外的其他佛珠在哪里。
    package collection;
     
    import java.util.LinkedList; 
    import charactor.Hero;
     
    public class TestCollection { 
        public static void main(String[] args) {
             
            //LinkedList是一个双向链表结构的list
            LinkedList<Hero> ll =new LinkedList<Hero>();
             
            //所以可以很方便的在头部和尾部插入数据
            //在最后插入新的英雄
            ll.addLast(new Hero("hero1"));
            ll.addLast(new Hero("hero2"));
            ll.addLast(new Hero("hero3"));
            System.out.println(ll);
             
            //在最前面插入新的英雄
            ll.addFirst(new Hero("heroX"));
            System.out.println(ll);
             
            //查看最前面的英雄
            System.out.println(ll.getFirst());
            //查看最后面的英雄
            System.out.println(ll.getLast());
             
            //查看不会导致英雄被删除
            System.out.println(ll);
            //取出最前面的英雄
            System.out.println(ll.removeFirst());
             
            //取出最后面的英雄
            System.out.println(ll.removeLast());
             
            //取出会导致英雄被删除
            System.out.println(ll);         
        }      
    }
    

    • 队列 - Queue
      LinkedList 除了实现了List和Deque外,还实现了Queue接口(队列)。
      Queue是先进先出队列 FIFO,常用方法:
      offer 在最后添加元素
      poll 取出第一个元素
      peek 查看第一个元素
    package collection;
      
    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("初始化队列:	");
            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()出来:	");
            //取出第一个Hero,FIFO 先进先出
            Hero h = q.poll();
            System.out.println(h);
            System.out.print("取出第一个元素之后的队列:	");
            System.out.println(q);
              
            //把第一个拿出来看一看,但是不取出来
            h=q.peek();
            System.out.print("查看peek()第一个元素:	");
            System.out.println(h);
            System.out.print("查看并不会导致第一个元素被取出来:	");
            System.out.println(q);          
        }       
    }
    

    • 使用LinkedList实现Stack栈
    package collection;
     
    import charactor.Hero;
     
    public interface Stack {
     
        //把英雄推入到最后位置
        public void push(Hero h);
        //把最后一个英雄取出来
        public Hero pull();
        //查看最后一个英雄
        public Hero peek();
    }
    
    package collection;
       
    import java.util.LinkedList;   
    import charactor.Hero;
       
    public class MyStack implements Stack{
       
        LinkedList<Hero> heros = new LinkedList<Hero>();
           
        @Override
        public void push(Hero h) {
            heros.addLast(h);
        }
       
        @Override
        public Hero pull() {
            return heros.removeLast();
        }
       
        @Override
        public Hero peek() {
            return heros.getLast();
        }
           
        public static void main(String[] args) {
               
            MyStack heroStack = new MyStack();
            for (int i = 0; i < 5; i++) {
                Hero h = new Hero("hero name " + i);
                System.out.println("压入 hero:" + h);
                heroStack.push(h);
            }
            for (int i = 0; i < 5; i++) {
                Hero h =heroStack.pull();
                System.out.println("弹出 hero" + h);
            }
        }   
    }
    

    二叉树

    • 二叉树
      二叉树由各种节点组成
      二叉树特点:
      每个节点都可以有左子节点
      右子节点每一个节点都有一个值
    package collection;
     
    public class Node {
        // 左子节点
        public Node leftNode;
        // 右子节点
        public Node rightNode;
        // 值
        public Object value;
    }
    
    • 二叉树排序-插入数据
    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);
            }  
        }
    }
    
    • 遍历
    package collection;
     
    import java.util.ArrayList;
    import java.util.List;
     
    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 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;
        }
      
        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);
            }
      
            System.out.println(roots.values());  
        }
    }
    

    HashMap

    • HashMap的键值对
      HashMap储存数据的方式是——键值对
    package collection;
       
    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不一样
    package collection;
      
    import java.util.HashMap;
      
    import charactor.Hero;
      
    public class TestCollection {
        public static void main(String[] args) {
            HashMap<String,Hero> heroMap = new HashMap<String,Hero>();
             
            heroMap.put("gareen", new Hero("gareen1"));
            System.out.println(heroMap);
             
            //key为gareen已经有value了,再以gareen作为key放入数据,会导致原英雄,被覆盖
            //不会增加新的元素到Map中
            heroMap.put("gareen", new Hero("gareen2"));
            System.out.println(heroMap);
             
            //清空map
            heroMap.clear();
            Hero gareen = new Hero("gareen");
             
            //同一个对象可以作为值插入到map中,只要对应的key不一样
            heroMap.put("hero1", gareen);
            heroMap.put("hero2", gareen);
             
            System.out.println(heroMap);
             
        }
    }
    
    • ArrayList 和 HashMap 性能对比
    import java.util.*;
    
    public class Test02 {
        public static void main(String[] args) {
            HashMap<String,Hero> heroHashMap = new HashMap<>();
            List<Hero> heroList = new ArrayList<>();
            for (int i = 0; i < 3000000; i++) {
                heroList.add(new Hero("hero in list "+i));
                heroHashMap.put("hero in hashmap "+i,new Hero("hashmap hero "+i));
            }
    
            long startL = System.currentTimeMillis();
            for (Hero hero : heroList) {
                if (hero.name.equals("hero in list 2626435")){
                    System.out.println(hero.name);
                }
                if (hero.name.equals("hero in list 126435")){
                    System.out.println(hero.name);
                }
                if (hero.name.equals("hero in list 326435")){
                    System.out.println(hero.name);
                }
            }
            long endL = System.currentTimeMillis();
            System.out.println("List查找时间:"+(endL-startL)+"ms");
    
            long startH = System.currentTimeMillis();
            System.out.println(heroHashMap.get("hero in hashmap 2626435"));
            System.out.println(heroHashMap.get("hero in hashmap 126435"));
            System.out.println(heroHashMap.get("hero in hashmap 326435"));
            long endH = System.currentTimeMillis();
            System.out.println("Hashmap查找时间:"+(endH-startH)+"ms");
        }
    }
    

    输出

    HashSet

    • Set中的元素,不能重复
    package collection;
      
    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中的元素,没有顺序。严格的说,是没有按照元素的插入顺序排列
      不保证Set的迭代顺序; 确切的说,在不同条件下,元素的顺序都有可能不一样
      换句话说,同样是插入0-9到HashSet中, 在JVM的不同版本中,看到的顺序都是不一样的。 所以在开发的时候,不能依赖于某种臆测的顺序,这个顺序本身是不稳定的
    package collection;
     
    import java.util.HashSet;
     
    public class TestCollection {
        public static void main(String[] args) {
            HashSet<Integer> numbers = new HashSet<Integer>();
     
            numbers.add(9);
            numbers.add(5);
            numbers.add(1);
     
            // Set中的元素排列,不是按照插入顺序
            System.out.println(numbers);
        }
    }
    

    • 遍历
      Set不提供get()来获取指定位置的元素,所以遍历需要用到迭代器,或者增强型for循环
    package collection;
      
    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);
            }         
        }
    }
    
    • HashSet和HashMap的关系
      HashSet自身并没有独立的实现,而是在里面封装了一个Map.HashSet是作为Map的key而存在的

    Collection

    Collection是 Set List Queue和 Deque的接口
    Queue: 先进先出队列
    Deque: 双向链表
    注:Collection和Map之间没有关系,Collection是放一个一个对象的,Map 是放键值对的
    注:Deque 继承 Queue,间接的继承了 Collection

    Collections

    Collections是一个类,容器的工具类,就如同Arrays是数组的工具类

    • 方法

    • 反转

    package collection;
       
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
       
    public class TestCollection {
        public static void main(String[] args) {
            //初始化集合numbers
            List<Integer> numbers = new ArrayList<>();
             
            for (int i = 0; i < 10; i++) {
                numbers.add(i);
            }
             
            System.out.println("集合中的数据:");
            System.out.println(numbers);
             
            Collections.reverse(numbers);
             
            System.out.println("翻转后集合中的数据:");
            System.out.println(numbers);         
        }
    }
    

    • 混淆
    package collection;
       
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
       
    public class TestCollection {
        public static void main(String[] args) {
            //初始化集合numbers
            List<Integer> numbers = new ArrayList<>();
             
            for (int i = 0; i < 10; i++) {
                numbers.add(i);
            }
             
            System.out.println("集合中的数据:");
            System.out.println(numbers);
             
            Collections.shuffle(numbers);
             
            System.out.println("混淆后集合中的数据:");
            System.out.println(numbers);         
        }
    }
    

    • 排序
    package collection;
       
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
       
    public class TestCollection {
        public static void main(String[] args) {
            //初始化集合numbers
            List<Integer> numbers = new ArrayList<>();
             
            for (int i = 0; i < 10; i++) {
                numbers.add(i);
            }
             
            System.out.println("集合中的数据:");
            System.out.println(numbers);
     
            Collections.shuffle(numbers);
            System.out.println("混淆后集合中的数据:");
            System.out.println(numbers);
     
            Collections.sort(numbers);
            System.out.println("排序后集合中的数据:");
            System.out.println(numbers);         
        }
    }
    

    • 交换
    package collection;
       
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
       
    public class TestCollection {
        public static void main(String[] args) {
            //初始化集合numbers
            List<Integer> numbers = new ArrayList<>();
             
            for (int i = 0; i < 10; i++) {
                numbers.add(i);
            }
             
            System.out.println("集合中的数据:");
            System.out.println(numbers);
     
            Collections.swap(numbers,0,5);
            System.out.println("交换0和5下标的数据后,集合中的数据:");
            System.out.println(numbers);         
        }
    }
    

    • 滚动
    package collection;
       
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
       
    public class TestCollection {
        public static void main(String[] args) {
            //初始化集合numbers
            List<Integer> numbers = new ArrayList<>();
             
            for (int i = 0; i < 10; i++) {
                numbers.add(i);
            }
             
            System.out.println("集合中的数据:");
            System.out.println(numbers);
     
            Collections.rotate(numbers,2);
            System.out.println("把集合向右滚动2个单位,标的数据后,集合中的数据:");
            System.out.println(numbers);         
        }
    }
    

    • 线程安全化
      synchronizedList 把非线程安全的List转换为线程安全的List。 因为截至目前为止,还没有学习线程安全的内容,暂时不展开。 线程安全的内容将在多线程章节展开。
    package collection;
     
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
     
    public class TestCollection {
        public static void main(String[] args) {
            List<Integer> numbers = new ArrayList<>();
     
            System.out.println("把非线程安全的List转换为线程安全的List");
            List<Integer> synchronizedNumbers = (List<Integer>) Collections.synchronizedList(numbers); 
        }
    }
    

    HashTable

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

    package collection;
     
    import java.util.HashMap;
    import java.util.Hashtable;
     
    public class TestCollection {
        public static void main(String[] args) {
             
            //HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式
             
            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); 
        }
    }
    

    泛型

    集合中的泛型

    • 不使用泛型
      不使用泛型带来的问题ADHero(物理攻击英雄) APHero(魔法攻击英雄)都是Hero的子类
      ArrayList 默认接受Object类型的对象,所以所有对象都可以放进ArrayList中
      所以get(0) 返回的类型是Object
      接着,需要进行强制转换才可以得到APHero类型或者ADHero类型。
      如果软件开发人员记忆比较好,能记得哪个是哪个,还是可以的。 但是开发人员会犯错误,比如第20行,会记错,把第0个对象转换为ADHero,这样就会出现类型转换异常
    package generic;
     
    import java.util.ArrayList;
     
    import charactor.ADHero;
    import charactor.APHero;
     
    public class TestGeneric {
     
        public static void main(String[] args) {
             
            ArrayList heros = new ArrayList();
             
            heros.add(new APHero());
            heros.add(new ADHero());
             
            APHero apHero =  (APHero) heros.get(0);
            ADHero adHero =  (ADHero) heros.get(1);
             
            //ADHero adHero2 =  (ADHero) heros.get(0); //出错
        }
    }
    
    • 使用泛型
      使用泛型的好处:泛型的用法是在容器后面添加
      Type可以是类,抽象类,接口
      泛型表示这种容器,只能存放APHero,ADHero就放不进去了。
    package generic;
     
    import java.util.ArrayList; 
    import charactor.APHero;
     
    public class TestGeneric {
     
        public static void main(String[] args) {
            ArrayList<APHero> heros = new ArrayList<APHero>();
             
            //只有APHero可以放进去    
            heros.add(new APHero());
             
            //ADHero甚至放不进去
            //heros.add(new ADHero());
             
            //获取的时候也不需要进行转型,因为取出来一定是APHero
            APHero apHero =  heros.get(0);         
        }
    }
    
    • 子类对象
      假设容器的泛型是Hero,那么Hero的子类APHero,ADHero都可以放进去
      和Hero无关的类型Item还是放不进去
    package generic;
     
    import java.util.ArrayList;
     
    import property.Item;
     
    import charactor.ADHero;
    import charactor.APHero;
    import charactor.Hero;
     
    public class TestGeneric {
     
        public static void main(String[] args) {
            ArrayList<Hero> heros = new ArrayList<Hero>();
             
            //只有作为Hero的子类可以放进去     
            heros.add(new APHero());
            heros.add(new ADHero());
             
            //和Hero无关的类型Item还是放不进去
            //heros.add(new Item());         
        }
    }
    
    • 泛型的简写
      为了不使编译器出现警告,需要前后都使用泛型,像这样:
      ArrayList<Hero> heros = new ArrayList<Hero>();
      不过JDK7提供了一个可以略微减少代码量的泛型简写方式
      ArrayList<Hero> heros2 = new ArrayList<>();
    package generic;
      
    import java.util.ArrayList; 
    import charactor.Hero;
      
    public class TestGeneric {  
        public static void main(String[] args) {
            ArrayList<Hero> heros = new ArrayList<Hero>();
            //后面可以只用<>
            ArrayList<Hero> heros2 = new ArrayList<>();         
        }
    }
    

    支持泛型的类

    • 不支持泛型的Stack
      以Stack栈为例子,如果不使用泛型
      当需要一个只能放Hero的栈的时候,就需要设计一个HeroStack
      当需要一个只能放Item的栈的时候,就需要一个ItemStack
    package generic;
       
    import java.util.LinkedList; 
    import charactor.Hero;
       
    public class HeroStack {
       
        LinkedList<Hero> heros = new LinkedList<Hero>();
           
        public void push(Hero h) {
            heros.addLast(h);
        }
       
        public Hero pull() {
            return heros.removeLast();
        }
       
        public Hero peek() {
            return heros.getLast();
        }
           
        public static void main(String[] args) {
               
            HeroStack heroStack = new HeroStack();
            for (int i = 0; i < 5; i++) {
                Hero h = new Hero("hero name " + i);
                System.out.println("压入 hero:" + h);
                heroStack.push(h);
            }
            for (int i = 0; i < 5; i++) {
                Hero h =heroStack.pull();
                System.out.println("弹出 hero" + h);
            }
        }   
    }
    
    package generic;
       
    import java.util.LinkedList;
     
    import property.Item;
       
    public class ItemStack {
       
        LinkedList<Item> Items = new LinkedList<Item>();
           
        public void push(Item h) {
            Items.addLast(h);
        }
       
        public Item pull() {
            return Items.removeLast();
        }
       
        public Item peek() {
            return Items.getLast();
        }
           
        public static void main(String[] args) {
               
            ItemStack ItemStack = new ItemStack();
            for (int i = 0; i < 5; i++) {
                Item item = new Item("Item name " + i);
                System.out.println("压入 Item:" + item);
                ItemStack.push(item);
            }
            for (int i = 0; i < 5; i++) {
                Item item =ItemStack.pull();
                System.out.println("弹出 Item" + item);
            }
        }   
    }
    
    • 支持泛型的Stack
      设计一个支持泛型的栈MyStack
      设计这个类的时候,在类的声明上,加上一个,表示该类支持泛型。
      T是type的缩写,也可以使用任何其他的合法的变量,比如A,B,X都可以,但是一般约定成俗使用T,代表类型。
    package generic;
       
    import java.util.HashMap;
    import java.util.LinkedList;
     
    import charactor.Hero;
    import property.Item;
       
    public class MyStack<T> {
       
        LinkedList<T> values = new LinkedList<T>();
           
        public void push(T t) {
            values.addLast(t);
        }
       
        public T pull() {
            return values.removeLast();
        }
       
        public T peek() {
            return values.getLast();
        }
           
        public static void main(String[] args) {
            //在声明这个Stack的时候,使用泛型<Hero>就表示该Stack只能放Hero
            MyStack<Hero> heroStack = new MyStack<>();
            heroStack.push(new Hero());
            //不能放Item
            heroStack.push(new Item());
             
            //在声明这个Stack的时候,使用泛型<Item>就表示该Stack只能放Item
            MyStack<Item> itemStack = new MyStack<>();
            itemStack.push(new Item());
            //不能放Hero
            itemStack.push(new Hero());
        }   
    }
    
    • 支持泛型的二叉树
    package collection;
     
    import java.util.ArrayList;
    import java.util.List;
     
    public class Node<T> {
        // 左子节点
        public Node<T> leftNode;
        // 右子节点
        public Node<T> rightNode;
      
        // 值
        public T value;
      
        // 插入 数据
        public void add(T t) {
            // 如果当前节点没有值,就把数据放在当前节点上
            if (null == value)
                value = t;
      
            // 如果当前节点有值,就进行判断,新增的值与当前值的大小关系
            else {
                // 新增的值,比当前值小或者相同
                 
                if ((Integer) t -((Integer)value) <= 0) {
                    if (null == leftNode)
                        leftNode = new Node<T>();
                    leftNode.add(t);
                }
                // 新增的值,比当前值大
                else {
                    if (null == rightNode)
                        rightNode = new Node<T>();
                    rightNode.add(t);
                }
      
            }
      
        }
      
     // 中序遍历所有的节点
        public List<T> values() {
            List<T> values = new ArrayList<>();
      
            // 左节点的遍历结果
            if (null != leftNode)
                values.addAll(leftNode.values());
      
            // 当前节点
            values.add(value);
      
            // 右节点的遍历结果
            if (null != rightNode)
      
                values.addAll(rightNode.values());
      
            return values;
        }
      
        public static void main(String[] args) {
      
            int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };
      
            Node<Integer> roots = new Node<>();
            for (int number : randoms) {
                roots.add(number);
            }
      
            System.out.println(roots.values());  
        }
    }
    

    通配符

    • ? extends
      ArrayList heroList<? extends Hero> 表示这是一个Hero泛型或者其子类泛型
      heroList 的泛型可能是
      HeroheroList 的泛型可能是APHero
      heroList 的泛型可能是ADHero
      所以 可以确凿的是,从heroList取出来的对象,一定是可以转型成Hero的
      但是,不能往里面放东西,因为
      放APHero就不满足
      放ADHero又不满足
    package generic;
       
    import java.util.ArrayList;  
    import charactor.ADHero;
    import charactor.APHero;
    import charactor.Hero;
       
    public class TestGeneric {
       
        public static void main(String[] args) {
              
            ArrayList<APHero> apHeroList = new ArrayList<APHero>();
            apHeroList.add(new APHero());
             
            ArrayList<? extends Hero> heroList = apHeroList;
              
            //? extends Hero 表示这是一个Hero泛型的子类泛型
              
            //heroList 的泛型可以是Hero
            //heroList 的泛型可以使APHero
            //heroList 的泛型可以使ADHero
              
            //可以确凿的是,从heroList取出来的对象,一定是可以转型成Hero的
              
            Hero h= heroList.get(0);
              
            //但是,不能往里面放东西
            //heroList.add(new ADHero()); //编译错误,因为heroList的泛型 有可能是APHero
        }      
    }
    
    • ? super
      ArrayList heroList<? super Hero> 表示这是一个Hero泛型或者其父类泛型
      heroList的泛型可能是Hero
      heroList的泛型可能是Object
      可以往里面插入Hero以及Hero的子类
      但是取出来有风险,因为不确定取出来是Hero还是Object
    package generic;
      
    import java.util.ArrayList;
      
    import charactor.ADHero;
    import charactor.APHero;
    import charactor.Hero;
      
    public class TestGeneric {
        public static void main(String[] args) {
      
            ArrayList<? super Hero> heroList = new ArrayList<Object>();
              
            //? super Hero 表示 heroList的泛型是Hero或者其父类泛型
              
            //heroList 的泛型可以是Hero
            //heroList 的泛型可以是Object
              
            //所以就可以插入Hero
            heroList.add(new Hero());
            //也可以插入Hero的子类
            heroList.add(new APHero());
            heroList.add(new ADHero());
              
            //但是,不能从里面取数据出来,因为其泛型可能是Object,而Object是强转Hero会失败
            //Hero h= heroList.get(0); //报错
        }  
    }
    
    • 泛型通配符?
      泛型通配符? 代表任意泛型
      既然?代表任意泛型,那么换句话说,这个容器什么泛型都有可能
      所以只能以 Object 的形式取出来
      并且不能往里面放对象,因为不知道到底是一个什么泛型的容器
    package generic;
      
    import java.util.ArrayList;
     
    import property.Item;
    import charactor.APHero;
    import charactor.Hero;
      
    public class TestGeneric {
      
        public static void main(String[] args) {
      
            ArrayList<APHero> apHeroList = new ArrayList<APHero>();
             
            //?泛型通配符,表示任意泛型
            ArrayList<?> generalList = apHeroList;
     
            //?的缺陷1: 既然?代表任意泛型,那么换句话说,你就不知道这个容器里面是什么类型
            //所以只能以Object的形式取出来
            Object o = generalList.get(0);
     
            //?的缺陷2: 既然?代表任意泛型,那么既有可能是Hero,也有可能是Item
            //所以,放哪种对象进去,都有风险,结果就什么什么类型的对象,都不能放进去
            //generalList.add(new Item()); //编译错误 因为?代表任意泛型,很有可能不是Item
            //generalList.add(new Hero()); //编译错误 因为?代表任意泛型,很有可能不是Hero
            //generalList.add(new APHero()); //编译错误  因为?代表任意泛型,很有可能不是APHero
        }
    }
    
    • 总结
      如果希望只取出,不插入,就使用? extends Hero
      如果希望只插入,不取出,就使用? super Hero
      如果希望,又能插入,又能取出,就不要用通配符?

    泛型转型

    • 对象转型
      子类转父类
    package generic;
     
    import charactor.ADHero;
    import charactor.Hero;
     
    public class TestGeneric { 
        public static void main(String[] args) {
     
            Hero h = new Hero();
            ADHero ad = new ADHero();
            //子类转父类
            h = ad;
        } 
    }
    
    • 子类泛型转父类泛型
      既然 子类对象 转 父类对象是可以成功的,那么子类泛型转父类泛型能成功吗?
      如代码
      hs的泛型是父类Hero
      adhs 的泛型是子类ADHero
    package generic;
     
    import java.util.ArrayList;
     
    import charactor.ADHero;
    import charactor.Hero;
     
    public class TestGeneric {
     
        public static void main(String[] args) {
            ArrayList<Hero> hs =new ArrayList<>();
            ArrayList<ADHero> adhs =new ArrayList<>();
     
            //子类泛型转父类泛型
            hs = adhs;
        } 
    }
    
    • 父类泛型不能转子类泛型
    package generic;
      
    import java.util.ArrayList;  
    import charactor.ADHero;
    import charactor.Hero;
      
    public class TestGeneric {
      
        public static void main(String[] args) {
            ArrayList<Hero> hs =new ArrayList<>();
            ArrayList<ADHero> adhs =new ArrayList<>();
      
            //假设能成功
            adhs = hs;
             
            //这个时候adhs实际上指向的是泛型是Hero的容器,而这个容器里可能放的是一个APHero
            //而根据泛型,直接取出来就转型成了ADHero
            //所以就变成了APHero转型成ADHero,这是矛盾的。
            ADHero ad =adhs.get(0);        
        }  
    }
    
  • 相关阅读:
    java多线程基础(一)
    重构总体思路
    【Gearman学习笔记】分布式处理入门
    virtualbox安装提示出现严重错误解决办法
    驱动程序vmci.sys版本不正确。请尝试重新安装 VMware
    Gearman任务分布系统部署windows平台_使用Cygwin
    Fatal error: Class 'GearmanClient' not found解决方法
    header('Content-type:text/html;charset = utf-8');出现中文乱码
    heredoc和nowdoc的区别
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
  • 原文地址:https://www.cnblogs.com/peng8098/p/java_03.html
Copyright © 2011-2022 走看看