04 集合

04 集合

###04.01 集合的概述

A:集合的由来
    * 数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少 
B:数组和集合的区别
    * 区别1 : 
        * 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值
        * 集合只能存储引用数据类型(对象)。集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象
    * 区别2:
        * 数组长度是固定的,不能自动增长
        * 集合的长度的是可变的,可以根据元素的增加而增长
C:数组和集合什么时候用
        * 1,如果元素个数是固定的推荐用数组
        * 2,如果元素个数不是固定的推荐用集合

###04.02 List的三个子类的特点
        ArrayList:
            底层数据结构是数组,查询快,增删慢。
            线程不安全,效率高。
        Vector:
            底层数据结构是数组,查询快,增删慢。
            线程安全,效率低。
        Vector相对ArrayList查询慢(线程安全的)
        Vector相对LinkedList增删慢(数组结构)
        LinkedList:
            底层数据结构是链表,查询慢,增删快。
            线程不安全,效率高。

        Vector和ArrayList的区别:
            Vector是线程安全的,效率低
            ArrayList是线程不安全的,效率高
        共同点:都是数组实现的

        ArrayList和LinkedList的区别:
            ArrayList底层是数组结果,查询和修改快
            LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢
        共同点:都是线程不安全的

###04.03 迭代器的原理
迭代器原理
    迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义hasNext()和next()方法,这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己迭代方式,
    这样做的好处有二, 第一:规定了整个集合体系的遍历方式都是hasNext()和next()方法;第二:代码有底层内部实现,使用者不用管怎么实现的,会用即可

###04.04 List集合的特有功能
List集合的特有功能概述
    * void add(int index,E element)   //index<= size且 >=0都不会异常
    * E remove(int index)       // 通过索引删除元素,删除的时候不会自动装箱
                        List lis = new ArrayList();
                        lis.add(111);  //添加的时候会自动装箱。
                        lis.add(222);
                        lis.add(333);
                        lis.remove(1); //是删除索引1处的元素,索引1处的元素是222.
    * E get(int index)     //获得指定位置处的索引
    * E set(int index,E element)   //将指定位置的元素修改
    
size()和get()方法结合使用遍历。
            List list = new ArrayList();
            list.add(new Student("张三", 18));
            list.add(new Student("李四", 18));
            list.add(new Student("王五", 18));
            list.add(new Student("赵六", 18));
            
            for(int i = 0; i < list.size(); i++) {
                Student s = (Student)list.get(i);
                System.out.println(s.getName() + "," + s.getAge());
            }

###04.05 集合框架(Vector的特有功能)
A:Vector类概述
B:Vector类特有功能
    * public void addElement(E obj)
    * public E elementAt(int index)
    * public Enumeration elements()
C:案例演示    
    * Vector的迭代
            Vector v = new Vector();                //创建集合对象,List的子类
            v.addElement("a");
            v.addElement("b");
            v.addElement("c");
            v.addElement("d");
            //Vector迭代
            Enumeration en = v.elements();            //获取枚举
            while(en.hasMoreElements()) {            //判断集合中是否有元素
                System.out.println(en.nextElement());//获取集合中的元素
            }
###04.06 泛型概述和基本使用
A:泛型概述
B:泛型好处
    * 提高安全性(将运行期的错误转换到编译期) 
    * 黄线消失
    * 省去强转的麻烦
C:泛型基本使用
    * <>中放的必须是引用数据类型 
D:泛型使用注意事项
    * 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型) 
    * 若定义Object类型可以接收任意类型,无意义,所以一般不定义成Object类型。 

###04.07 泛型的由来
A:案例演示
    * 泛型的由来:通过Object转型问题引入
    * 早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。

###04.08 泛型类的概述及使用
A:泛型类概述<T>
    * 把泛型定义在类上
B:定义格式
    * public class 类名<泛型类型1,…>
    * public class Tool<Q>{
          ....
      }
C:注意事项    
    * 泛型类型必须是引用类型
D:案例演示
    * 泛型类的使用

###04.09 泛型方法的概述和使用)
A:泛型方法概述
    * 把泛型定义在方法上
B:定义格式    
    * public <泛型类型> 返回类型 方法名(泛型类型 变量名)  
     public<T> void show(T t){
          System.out.println(t); 
      }   
    public static<W> void print(W w){ 
        System.out.prinln(w);
    }
C:案例演示
    * 泛型方法的使用            
 //非静态方法泛型最好与类的泛型一致;如果不一致,需要在方法上声明该泛型。
 //静态方法必须声明自己的泛型(随着类的加载而加载);一般是跟类的泛型不一样。和类的声明相同是可以的,一个是创建对象时赋值,一个是调用静态方法时赋值,相当于两个变量

###04.10 泛型接口 的概述和使用
A:泛型接口概述
    * 把泛型定义在接口上
B:定义格式    
    * public interface 接口名<泛型类型>  
C:案例演示
    * 泛型接口的使用
//没有必要在实现接口的时候给自己类加泛型。所以一般随接口的泛型。
interface Inter<T> {
    public void show(T t);
}

/*class Demo implements Inter<String> {      //推荐用这种
    @Override
    public void show(String t) {
        System.out.println(t);
    }    
}*/
class Demo<T> implements Inter<T> {    //没有必要在实现接口的时候给自己类加泛型
    @Override
    public void show(T t) {
        System.out.println(t);
    }    
}

###04.11 泛型高级之通配符
A:泛型通配符<?>
    * 任意类型,如果没有明确,那么就是Object以及任意的Java类了  
        List<?> list = new ArrayList<Integer>();    //当右边的泛型是不确定时,左边可以指定为?
B:? extends E
    * 向下限定,E及其子类         
C:? super E
    * 向上限定,E及其父类


###04.12  增强for的概述和使用
A:增强for概述
    * 简化数组和Collection集合的遍历 ,底层依赖的是叠加器
B:格式:
        for(元素数据类型 变量 : 数组或者Collection集合) {
            使用变量即可,该变量就是元素
        }
C:案例演示
    * 数组,集合存储元素用增强for遍历
D:好处
    * 简化遍历

###04.13 ArrayList存储字符串和自定义对象并遍历增强for版
A:案例演示
    * ArrayList存储字符串并遍历增强for版
            ArrayList<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            list.add("d");
            for(String s : list) {
                System.out.println(s);
            }
###04.14 三种迭代的能否删除
    * 普通for循环,可以删除,但是 索引要--(list.remove(i--);)。 //不会出现越界异常,因为--马上又++了。

    * 迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常

    * 增强for循环不能删除

###04.15 静态导入的概述和使用 jdk5.0新特新
A:静态导入概述 ,就是导入类中的静态方法
B:格式:
    * import static 包名….类名.方法名;
    * import static java.util.Arrays.sort;     //静态导入
    * import static java.util.Arrays.*;     //把类中的静态方法都导入    
    * import static java.util.Arrays.toString;  //静态导入
C:注意事项
    * 方法必须是静态的,如果有多个同名的静态方法,就不知道使用的是哪个?这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。

###04.16 可变参数 的概述和使用 jdk5.0新特新 
A:可变参数概述
    * 定义方法的时候不知道该定义多少个参数  //可以接收很多参数。。
B:格式
    * 修饰符 返回值类型 方法名(数据类型…  变量名){}
C:注意事项:
    * 这里的变量其实是一个数组
    * 如果一个方法有可变参数,还有多个参数,那么可变参数必须放在最后一个
print(11,22,33,44,55);
print(11,arr),  //arr是一个int数组,11是赋值给x的
public static void print(int x,int ... arr){
        for (int i : arr) {
            System.out.print(i+" ");
        }
    }

###04.17 Arrays工具类的asList()方法的使用
A:案例演示  ,数组转集合
    * Arrays工具类的asList()方法的使用                 
    * Collection中toArray(T[] a)泛型版的集合转数组     
//数组转换成集合虽然不能增加或减少元素,但是可以利用集合的思想操作数组,可以使用集合中的其他方法。
//基本数据类型的数组是把整个数组当成一个元素存入集合。所以数组转换成集合,数组必须是引用数据类型。
public class Demo4_AsList {
    public static void main(String[] args) {
        //demo1();
        //demo2();
        //集合转数组,加泛型的
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        //String[] arr = list.toArray(new String[1]);    
            //Integer[] arr = al.toArray(new Integer[10]);
            //Object[] arr = al.toArray();
        String[] arr = list.toArray(new String[10]);        
          //当集合转换数组时,数组长度如果是小于等于集合的size时,转换后的数组长度等于集合的size
           //如果数组的长度大于了size,分配的数组长度就和你指定的长度一样
        for (String string : arr) {
            System.out.println(string);
        }
    }

    public static void demo2() {
        //int[] arr = {11,22,33,44,55};            
        //List<int[]> list = Arrays.asList(arr);     //基本数据类型的数组转换成集合,会将整个数组当作一个对象转换
        //System.out.println(list);
        Integer[] arr = {11,22,33,44,55};           //将数组转换成集合,数组必须是引用数据类型
        List<Integer> list = Arrays.asList(arr);
        System.out.println(list);
    }

    public static void demo1() {
        String[] arr = {"a","b","c"};
        List<String> list = Arrays.asList(arr);        //将数组转换成集合,是List集合接收
        //list.add("d");                            //不能添加元素
        System.out.println(list);
    }
}

###04.18 ArrayList嵌套ArrayList)
A:案例演示
    * 集合嵌套之ArrayList嵌套ArrayList  //二维集合。。
    public static void main(String[] args) {
        ArrayList<ArrayList<Person>> list = new ArrayList<>();
        
        ArrayList<Person> first = new ArrayList<>();                //创建第一个班级
        first.add(new Person("杨幂", 30));
        first.add(new Person("李冰冰", 33));
        first.add(new Person("范冰冰", 20));
        
        ArrayList<Person> second = new ArrayList<>();
        second.add(new Person("黄晓明", 31));
        second.add(new Person("赵薇", 33));
        second.add(new Person("陈坤", 32));
        
        //将班级添加到学科集合中
        list.add(first);
        list.add(second);
        
        //遍历学科集合
        for(ArrayList<Person> a : list) {
            for(Person p : a) {
                System.out.println(p);
            }
        }
    }

###04.19 HashSet存储自定义对象保证元素唯一性
A:案例演示
    * 存储自定义对象,并保证元素唯一性。
            HashSet<Person> hs = new HashSet<>();
            hs.add(new Person("张三", 23));
            hs.add(new Person("张三", 23));
            hs.add(new Person("李四", 23));
            hs.add(new Person("李四", 23));
            hs.add(new Person("王五", 23));
            hs.add(new Person("赵六", 23));
重写hashCode()和equals()方法
    * 1.HashSet原理
        * 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数
        * 当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象
            * 如果没有哈希值相同的对象就直接存入集合
            * 如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存
    * 2.将自定义类的对象存入HashSet去重复
        * 类中必须重写hashCode()和equals()方法
        * hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
        * equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储
        
        public boolean equals(Object obj) {
            if (this == obj)
                return true; //调用的对象与传入的对象是同一个对象,返回true
            if (obj == null)   
                return false;   //传入的对象为null,返回false  (调用的对象不可能是null,否则会出现异常)
            if (getClass() != obj.getClass())  
                return false;     //判断两个字节码文件是否是同一个,不是直接返回false
            Person other = (Person) obj;  // 是,转换类型,这样不会出现类型转换异常
            if (age != other.age)
                return false;    //调用对象的年龄不等于传入对象的年龄
            if (name == null) {  //调用对象的年龄为null,(这是对象的属性name为null  不是对象为null)
                if (other.name != null)
                    return false;
            } else if (!name.equals(other.name))  //调用对象的姓名不等于传入对象的姓名
                return false;
            return true;
        }

###04.20 TreeSet原理
1.特点
    * TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
2.使用方式
    * a.自然顺序(Comparable)
        * TreeSet类的add()方法中会把存入的对象提升为Comparable类型
        * 调用对象的compareTo()方法和集合中的对象比较
        * 根据compareTo()方法返回的结果进行存储
    * b.比较器顺序(Comparator)
        * 创建TreeSet的时候可以制定 一个Comparator
        * 如果传入了Comparator接口的子类对象, 那么TreeSet就会按照比较器中的顺序排序
        * add()方法内部会自动调用Comparator接口中compare()方法排序
        * 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
    * c.两种方式的区别
        * TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
        * TreeSet如果传入Comparator, 就优先按照Comparator
###04.21 键盘录入学生信息按照总分排序后输出在控制台
需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩)");
            TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
                @Override
                public int compare(Student s1, Student s2) {
                    int num = s2.getSum() - s1.getSum();            //根据学生的总成绩降序排列
                    return num == 0 ? 1 : num;
                }
            });
            
            while(ts.size() < 5) {
                String line = sc.nextLine();
                try {
                    String[] arr = line.split(",");
                    int chinese = Integer.parseInt(arr[1]);                //转换语文成绩
                    int math = Integer.parseInt(arr[2]);                //转换数学成绩
                    int english = Integer.parseInt(arr[3]);                //转换英语成绩
                    ts.add(new Student(arr[0], chinese, math, english));
                } catch (Exception e) {
                    System.out.println("录入格式有误,输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩");
                }
                
            }
            
            System.out.println("排序后的学生成绩是:");
            for (Student s : ts) {
                System.out.println(s);
            }

public class Student {
    private String name;
    private int chinese;
    private int math;
    private int english;
    private int sum;  //
    public Student() {
        super();
    }
    public Student(String name, int chinese, int math, int english) {
        super();
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
        this.sum =this.chinese + this.math + this.english;  //
    }
    public int getSum() { //
        return sum;
    }
    @Override
    public String toString() {
        return "姓名"+name+",语文"+chinese+",数学"+math+",英语"+english+",总成绩"+sum;
    }
}

###04.22 Map集合概述和特点
A:Map接口概述
    * 查看API可以知道:
        * 将键映射到值的对象
        * 一个映射不能包含重复的键
        * 每个键最多只能映射到一个值
B:Map接口和Collection接口的不同
    * Map是双列的,Collection是单列的
    * Map的键唯一,Collection的子体系Set是唯一的
    * Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效

###04.23 HashMap和Hashtable的区别
A:面试题
    * HashMap和Hashtable的区别
        * Hashtable是JDK1.0版本出现的,是线程安全的,效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
        * Hashtable不可以存储null键和null值;HashMap可以存储null键和null值,使后面的代码能继续运行下去
        * Hashtable是类命名没有按约定的规则
B:案例演示    
    * HashMap和Hashtable的区别
    * Hashtable<Integer,String> ht = new Hashtable<>();
        ht.put(null, "国民老公");
        ht.put(33, "null");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值