Java-集合、泛型

目录

1 集合

1.1集合的框架体系

1.2 Collection接口的常用方法

1.3 迭代器遍历

2 List接口

2.1 List接口和常用方法

2.2 ArrayList 分析

2.3 Vector类

2.4 LinkedList类

3 Set

3.1 Set接口和常用方法

3.2 HashSet

3.3 LinkedHashSet

3.4 TreeSet

4 Map

4.1 Map接口和常用方法

4.2 Map的遍历方法

4.3 HashMap

4.4 Hashtable

4.5 Properties

4.6 TreeMap

5 开发中如何选择集合实现类

6 Collections工具类

6.1 Collections工具类介绍

6.2 排序操作

6.3 查找操作

7 泛型

7.1 泛型引入

7.2 泛型介绍

7.3 泛型的语法

7.4 自定义泛型类

7.5 自定义接口

7.6 自定义泛型方法

7.7 泛型的继承和通配符

8 JUnit的使用

1 集合

1.1集合的框架体系

1): 集合主要是两组(单列集合 , 双列集合)

2):Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合

3): Map 接口的实现子类 是双列集合,存放的 K-V

1.2 Collection接口的常用方法

1):Collection实现子类可以存放多个元素,每个元素是Object

2):部分Collection的实现类,可以存放重复元素,有些不可以

3):部分Collection的实现类,有些是有序的,有些无序

4):Collection接口没有直接的实现子类,是通过它的子接口List和Set来实现的

5):add(),添加单个元素

6):remove(),删除指定元素

7):contains(),查找元素是否存在

8):size(),获取元素个数

9):isEmpty(),判断是否为空

10):clear(),清空

11):addAll(集合),添加多个元素

12):containsAll(集合),查找多个元素是否都存在

13):removeAll(集合),删除多个元素

public class Collection_ {
    public static void main(String[] args) {
        //以ArrarList为例
        List list = new ArrayList();
        // add:添加单个元素
        list.add("jack");
        list.add(0);//
        // 自动装箱list.add(new Integer(10))
        list.add(true);
        System.out.println("list=" + list);
        // remove:删除指定元素
        //list.remove(0);删除第一个元素,输入数字就是删除的指定下标的元素
        Integer integer = 0;
        list.remove(integer);//指定删除某个元素
        System.out.println("list=" + list);
        // contains:查找元素是否存在
        System.out.println(list.contains("jack"));//T
        // size:获取元素个数
        System.out.println(list.size());//2
        //isEmpty:判断是否为空
        System.out.println(list.isEmpty());//F
        // clear:清空
        list.clear();
        System.out.println("list=" + list);
        // addAll:添加多个元素
        ArrayList list2 = new ArrayList();
        list2.add("红楼梦");
        list2.add("三国演义");
        list.addAll(list2);
        System.out.println("list=" + list);
        // containsAll:查找多个元素是否都存在
        System.out.println(list.containsAll(list2));//T
        list.add("聊斋");
        // removeAll:删除多个元素
        list.removeAll(list2);
        System.out.println("list=" + list);//[聊斋]
        // 说明:以 ArrayList 实现
    }
}

1.3 迭代器遍历

1):Collection接口遍历元素方式1-使用Iterator(迭代器)

2):Iterator对象称为迭代器,主要用于遍历Collection集合中元素

3):所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,既可以返回一个迭代器

4):Iterator仅用于遍历集合,Iterator本身并不存放对象

5):Iterator接口的方法,hasNext():判断是否还有下一个对象;next():指针下下移,返回对象,先调用hasNext(),再调用next(),快捷键itit

6):如果希望再次遍历,需要重置迭代器iterator = col.iterator();

7):增强for是简化版本的,输入I快捷键

public class Iterator_ {
    public static void main(String[] args) {
        ArrayList col = new ArrayList();
        col.add(new Book("三国演义", "罗贯中", 10));
        col.add(new Book("小李飞刀", "古龙", 5));
        col.add(new Book("红楼梦", "曹雪芹", 34));
        //现在希望能够遍历 col 集合
        //1. 先得到 col 对应的 迭代器
        Iterator iterator = col.iterator();
        //2. 使用 while 循环遍历
        // while (iterator.hasNext()) {//判断是否还有数据
        //返回下一个元素,类型是 Object
        // Object obj = iterator.next();
        // System.out.println("obj=" + obj);
        // }
        //快速生成 while->itit
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println("obj:"+next);
        }
        //再次使用,需要重置迭代器
        iterator = col.iterator();
        //增强for循环
        for(Object book:col)
        {
            System.out.println(book);
        }
    }
}
class Book{
    private  String name;
    private String auther;
    private int price;

    public Book(String name, String auther, int price) {
        this.name = name;
        this.auther = auther;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuther() {
        return auther;
    }

    public void setAuther(String auther) {
        this.auther = auther;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", auther='" + auther + '\'' +
                ", price=" + price +
                '}';
    }
}

2 List接口

2.1 List接口和常用方法

List接口是Collection接口的子接口

1):List集合类中元素有序(添加顺序和取出顺序一致),且可重复

2):List集合中的每个元素都有其对应的顺序索引,即支持索引

3):List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

4):List接口的实现类有,ArraryLis、LinkedList和Vector

5):add(int,object),在int位置插入元素或直接在末尾插入元素

6):add(int,Collection),在int位置将集合插入进去

7):get(int),获得int位置处的元素,从0开始

8):indexOf(Object),返回元素在集合中首次出现的位置

9):lastIndexOf(Object),返回元素在集合中最后一次出现的位置

10):remove(int),移除指定int位置的元素

11):set(int,Object),设置指定int位置的元素为Object,替换

12):subList(int,int),返回指定序列的子集合

public class List_ {
    public static void main(String[] args) {
        //1. List 集合类中元素有序(即添加顺序和取出顺序一致)、且可重复 [案例]
        List list1 = new ArrayList();
        list1.add("jack");
        list1.add("tom");
        List list2 = new ArrayList();
        list2.add(222);
        list2.add(222);
        //2. List 集合中的每个元素都有其对应的顺序索引,即支持索引
        // 索引是从 0 开始的
        System.out.println("get():"+list2.get(1));//tom
        System.out.println(list1.addAll(list2));
        System.out.println("list1添加了list2:"+list1);
        System.out.println(list1.indexOf("tom"));
        //int:移除指定下标的元素,Object:删除对应的元素,只删除一次
        System.out.println("remove前"+list2);
        System.out.println(list2.remove((Integer)222));
        System.out.println("remove后"+list2);
        //替换,索引必须存在
        System.out.println(list1.set(0,"4"));
        System.out.println(list1);
        //int1<=sublist<int2
        System.out.println(list1.subList(1,3));
    }
}

13):练习

public class Exercise {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Book("红楼梦","曹雪芹",156));
        arrayList.add(new Book("西游记","吴承恩",46));
        arrayList.add(new Book("水浒传","施耐庵",96));
        arrayList.add(new Book("三国演义","罗贯中",36));
        sort(arrayList);
        for(Object ob:arrayList){
            System.out.println("输出"+ob);
        }
    }
    public static List sort(List list){
        int len=list.size();
        for (int i = 0; i < len-1; i++) {//比较的轮数
            for (int j=0;j<len-1-i;j++){//一轮中比较的次数
                Book book1=(Book) list.get(j);
                Book book2=(Book) list.get(j+1);
                if(book1.getPrice()>book2.getPrice()){
                    list.set(j,book2);
                    list.set(j+1,book1);
                }
            }
        }
        return list;
    }
}
class Book{
    private String name;
    private String auther;
    private int price;

    public Book(String name, String auther, int price) {
        this.name = name;
        this.auther = auther;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuther() {
        return auther;
    }

    public void setAuther(String auther) {
        this.auther = auther;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "名称:" +
                "name='" + name + '\'' +
                ", auther='" + auther + '\'' +
                ", price=" + price ;
    }
}

2.2 ArrayList 分析

1):ArrayList可以加入null,并且可以多个

2):ArrayList是由数组来实现数据存储的

3):ArrayList基本等同于Vector,ArrayList是线程不安全的(但执行效率高),多线程不要使用

4):ArrayList中维护了一个Object类型的数组elementData

5):当创建对象时,如果使用的是无参构造器,则初始化elementData容量为0

6):当添加元素时,先判断是否需要扩容,如果需要,则调用grow(),否则直接添加元素到合适位置

7):如果使用的是无参构造器,如果第一次添加,则扩容elementData为10,如果需要再次扩容,则扩容为elementData的1.5倍

8):如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity

9):如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍

2.3 Vector类

1):Vector底层是一个对象数组,protected Object[] elementData

2):Vector是线程同步的,即线程安全,开发中,需要线程同步安全时,优先考虑使用Vector

3):如果使用的是无参构造器,默认10,后面按照2倍扩容

4):如果指定大小,则直接按2倍扩容

2.4 LinkedList类

1):LinkedList底层实现了双向链表和双端队列特点

2):可以添加任意元素(元素可以重复),包括null

3):线程不安全,没有实现同步

4):LinkedList中维护了两个属性first和last分别指向首节点和尾节点

5):每个节点(Node对象),里面又维护了prev、next、item三个属性,prev指向前一个、next指向后一个节点,最终实现双向链表

6):LinkedList元素的添加和删除不是通过数组来完成的,所以效率较高

7):单线程时:如果改查较多选择ArrayList,增删较多选择LinkedList,一般都是改查较多

3 Set

3.1 Set接口和常用方法

和List一样是Collection的子接口,因此,常用方法和它一样

1):无序(添加和取出顺序不一致),但是取出顺序固定,没有索引

2):不允许重复元素,所以最多包含一个null

3):Set接口的实现类有:HashSet、TreeSet...

4):Set不能通过索引获取,只能用迭代器和增强for获得

3.2 HashSet

1): HashSet实现了Set,第一次添加时系统扩容到16,阙值为12(0.75),到达阙值二倍扩容

2): HashSet实际上是 HashMap,table(数组)中每个元素对应一个链表(hash值相同的但是内容不同的)

3):可以存null,只能有一个

4): HashSet无序,不保证元素跟存入时的顺序一致,取决于hash后,在确定索引的结果

5):不能有重复元素

6):HashSet添加一个元素时,先得到hash值-会转成->索引值

7):HashSet找到存储数据表table,看这个索引位置是否已经存放元素

8):如果有,调用equals比较,相同放弃添加,不相同添加到最后

9):在jdk8中,如果一条链表的元素个数到达默认值8,并且table大于等于64,就会进行树化(红黑树)

public class Set_ {
    public static void main(String[] args) {
        Set hashSet = new HashSet();
        hashSet.add(55);
        hashSet.add(66);
        hashSet.add(null);
        hashSet.add(55);
        System.out.println(hashSet);//取出顺序固定,但不是开始存入的顺序,不存放重复元素,可以添加null
        hashSet=new HashSet();
        hashSet.add(new Dog("tom"));//ok
        hashSet.add(new Dog("tom"));//ok
        hashSet.add(new String("hsp"));//ok
        hashSet.add(new String("hsp"));//加入不了.
        System.out.println("set=" + hashSet);
        
    }
}
class Dog{
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }
}

10):练习

public class Exercise {
    public static void main(String[] args) {
        /*定义一个 Employee 类,该类包含:private 成员属性 name,age 要求:
        创建 3 个 Employee 对象放入 HashSet 中
        当 name 和 age 的值相同时,认为是相同员工, 不能添加到 java.util.HashSet 集合*/
        //加入时,先比较code再调用equals
        HashSet hashSet = new HashSet();
        hashSet.add(new Person("lll",20));
        hashSet.add(new Person("www",19));
        hashSet.add(new Person("lll",20));//修改equals()和hashCode()后不可以添加相同的
        System.out.println(hashSet);
    }
}
class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

 11):练习2,当A要修改code值和equals()包含B类时,A类中的属性类型是B类,B类也要修改code值和equals(),因为A类需要根据比较属性的hash返回不同的hash值,A类中的属性类型有B类,即B类要根据内容比较返回不同的hash值,否则如果不重写hashCode()相同内容由于new的原因,返回的是不同的hash值,B类的内容相同却返回了不同的hash值,导致A连锁反应,两个A对象内容相同hash值却不同,导致错误的成功添加到HashSet。equals()同理,hash相同则在同一个链表然后调用equals(),如果B类不重写equals(),导致A连锁,相同内容equals()返回false,最后导致两个A对象内容相同却可以成功添加到HashSet。

public class Exercise2 {
    public static void main(String[] args) {
//定义一个Employee类,该类包含:private成员属性name,sal,birthday(MyDate类型),
//其中 birthday 为 MyDate类型(属性包括:year, month, day),要求:
//当 name 和 age 的值相同时,认为是相同员工, 不能添加到 HashSet
        HashSet hashSet = new HashSet();
        hashSet.add(new Employee("jeff",520,new MyDate(2002,10,7)));
        hashSet.add(new Employee("jeff",820,new MyDate(2002,10,7)));
        System.out.println(hashSet);
    }
}
class Employee{
    private  String name;
    private  double sal;
    private MyDate date;

    public Employee(String name, double sal, MyDate date) {
        this.name = name;
        this.sal = sal;
        this.date = date;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(name, employee.name) && Objects.equals(date, employee.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name,  date);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", date=" + date +
                '}';
    }
}
class MyDate{
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public String toString() {
        return year + "- " + month + "-" + day ;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return year == myDate.year && month == myDate.month && day == myDate.day;
    }

    @Override
    public int hashCode() {
        return Objects.hash(year, month, day);
    }
}

3.3 LinkedHashSet

1):LinkedHashSet是HashSet的子类

2):LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表

3):LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使元素看起来是以插入顺序保存的

4):LinkedHashSet不允许添重复元素

5):在LinkedHastSet中维护了一个hash表和双向链表(LinkedHashSet有head和tail)
6):每一个节点有pre和next属性,这样可以形成双向链表

7):在添加一个元素时,先求hash值,在求索引.,确定该元素在hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset一样])

8):tail.next = newElement;newElement.pre = tail;tail = newEelment;这样就形成了双向链表,使元素顺序跟加入时的顺序一致

9):添加第一次时,直接将table扩容到16

3.4 TreeSet

1):使用无参构造器创建时,仍然是无序的,以添加的对象实现的Comparable接口的compareTo()方法去重,后面添加时如果添加的对象A没有实现Comparable接口则报错,因为底层会把对象A转成Comparable

2):使用TreeSet提供的一个构造器,可以传入一个比较器去重


public class TreeSet_ {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();//实际上是调用String的compareTo方法进行遍历比较
        treeSet.add("r");
        treeSet.add("r");
        System.out.println(treeSet);
    }
}
public class TreeSet_ {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //调用String的compareTo()进行比较,从首字母开始比较
                return (((String)o1).length()-((String) o2).length());
            }
        });//return 0的时候数据不会加入进去,规则的设置会导致=0的数据加不进去
        treeSet.add("aaa");
        treeSet.add("r");
        treeSet.add("rrr");//无法加入,以长度为比较器加入
        System.out.println(treeSet);
    }
}

4 Map

4.1 Map接口和常用方法

1):Map和Collection接口并列存在,用于保存具有隐射关系的数据Key-Value

2):Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中

3):Map中的key不允许重复(Set),原因和HashSet一样,code和equals

4):Map中的value可以重复(Collection)

5):Map中的key和value都可以为null

6):常用String类作为Map的key

7):key和value之间存在单向一对一关系,即通过指定key总的找到对应的value

8):Map存放数据,一对K-V是放在一个HashMap$Node(table表【数组+单向链表+红黑树(64)】)中的,是因为Node实现了Entry接口,有些书上也说,一对K-V就是一对Entry(为了遍历方便所以EntrySet指向table中的真正的数据)

9):put(),添加

10):remove(),根据键删除映射关系

11):get(),根据键获取值

12):size(),获取元素个数

13):isEmpty(),判断个数是否为空

14):clear(),清除

15):containsKey(),查找键是否存在

16):HashMap(),线程不安全

public class Map_ {
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        hashMap.put("k01","赵露丝");
        hashMap.put("k01","替换");
        hashMap.put("k02","");
        hashMap.put("","杨幂");
        hashMap.put(3,"杨幂");
        hashMap.put("k04","鞠婧祎");
        //无序,key不能重复,key重复了就替换,key、value都可以为null
        System.out.println(hashMap);
        //get(),根据key的值返回value
        System.out.println(hashMap.get("k03"));
        //删除对应的key和value,返回key对应移除的value
        System.out.println(hashMap.remove("k01"));
        System.out.println(hashMap);
        System.out.println(hashMap.size());
        System.out.println(hashMap.isEmpty());
        System.out.println(hashMap.containsKey("k04"));
        hashMap.clear();
        System.out.println(hashMap);
    }
}

4.2 Map的遍历方法

1):keySet(),获取所有的键

2):entrySet(),获取所有关系

3):values(),获取所有的值

             //遍历方式1 KeySet
        Set keyset=hashMap.keySet();
        System.out.println("-----------方法一增强for--------");
        for(Object obj:keyset){
            System.out.println(obj+"++"+hashMap.get(obj));
        }
        System.out.println("-----------方法一迭代器--------");
        Iterator iterator = keyset.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next+"++"+hashMap.get(next));
        }
        //遍历方法2
        System.out.println("-----------方法二取出所有的value--------");
        Collection values = hashMap.values();
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()) {
            Object next =  iterator1.next();
            System.out.println("只能取出value"+next);
        }
        //遍历方法3,EntrySet
        System.out.println("-----------方法三增强for--------");
        Set set = hashMap.entrySet();
        for (Object o:set){
            Map.Entry m=(Map.Entry)o;
            System.out.println(m.getKey()+"-"+m.getValue());
        }
        System.out.println("-----------方法三迭代器--------");
        Iterator iterator2 = set.iterator();
        while (iterator2.hasNext()) {
            Object next =  iterator2.next();
            Map.Entry m=(Map.Entry)next;
            System.out.println(m.getKey()+"-"+m.getValue());
        }

4.3 HashMap

1):HashMap底层维护了Node类型的数组table,默认值为null

2):当创建对象时,将加载因子(loadfactor)初始化为0.75,初始化Node类型的数组table

3):当添加key-val时,通过key的哈希值得到在table的索引,然后判断该索引处是否有元素,如果没有元素直接添加,如果该索引处有元素,继续判断该元素的key是否和准备加入的key相等,如果相等,则直接替换val;如果不相等(key不相等hash相等)和后面的继续比较、有相等的替换然后break不相等加在后面,需要判断是树结构还是链表结构,做出相应的处理(链表:则调用equals循环比较都不相等则加在后面,有相等的则进行替换),如果添加时发现容量不够则扩容

4):第一次添加,需要扩容table容量为16,临界值(threshold)为12,到了临界值就扩容

5):以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,以此类推

6):在Java8中,如果一条链表的元素超过8(TREEIFY_THRESHOLD)并且table>=64(MIN_TREEIFY_CAPACITY)就会进行树化

4.4 Hashtable

1):存放的元素是键值对即K-V

2):Hashtable的键和值都不能为null

3):Hashtable使用方法基本上和HashMap一样

4):Hashtable是线程安全的

5):底层有数组Hashtable$Entry[]初始化大小为11,临界值是11*0.75=8

6):扩容:到了临界值扩容(例如到了8个则扩容到23),扩容到原来的2倍+1

4.5 Properties

1):Properties类继承Hashtable类并实现了Map接口,也是使用键值对的形式来保存数据

2):Properties的使用特点和Hashtable类似,key和value不能为null,相同的键替换

3):Properties还可用于xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改

4):工作后  xxx.properties文件通常作为配置文件

4.6 TreeMap

1):使用默认构造器创建TreeMap无序

2):使用传入比较器的构造器创建,可以指定规则有序

5 开发中如何选择集合实现类

1):先判断存储类型-一组对象还是一组键值对

2):一组对象Collection接口,

允许重复:List【有序】

        增删多:LinkedList[底层维护了一个双向链表]

        改查多:ArrayList[底层维护Object类型的可变数组]

不允许重复:Set

        无序:HashSet[底层是HashMap,维护了一个哈希表,数组+链表+红黑树]

        排序:TreeSet

        插入和取出顺序一致:LinkedHashSet,维护数组+双向链表

3):一组键值对:Map

 键无序:HashMap[底层是:哈希表 数组+链表+红黑树]

 键排序:TreeMap

 键插入和取出顺序一致:LinkedHashMap

 读取文件:Properties

6 Collections工具类

6.1 Collections工具类介绍

1):Collections工具类是一个操作Set、List和Map等集合的工具类

2):Collections工具类中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作

6.2 排序操作

1):reverse(List),反转List中元素的顺序

2):shuffle(List),对List集合元素进行随机排序

3):sort(List),根据元素的自然顺序对指定List集合元素按升序排序

4):sort(List,Comparator),根据指定的Comparator产生的顺序对List集合进行排序

5):swap(List,int,int),将指定List集合中的i处元素和j处元素进行交换

6.3 查找操作

1): Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
2):Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
3):Object min(Collection)
4):Object min(Collection,Comparator)
5): int frequency(Collection,Object):返回指定集合中指定元素的出现次

6):void copy(List dest,List src):将src中的内容复制到dest中,我们需要先给 dest 赋值,大小和 list.size()一样

7):boolean replaceAll(List list,Object oldVal,Object newVal):使用
新值替换List对象的所有旧值

7 泛型

7.1 泛型引入

1): 当我们 ArrayList 表示存放到 ArrayList 集合中的元素是 Dog 类型 (细节后面说...)

2): 如果编译器发现添加的类型,不满足要求,就会报错

3): 在遍历的时候,用增强for循环可以直接取出 Dog 类型而不是 Object,for(Dog o:arraylist)

4): public class ArrayList<E> {} E 称为泛型,那么 Dog->E

ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 10));
arrayList.add(new Dog("发财", 1));
arrayList.add(new Dog("小黄", 5)
//arrayList.add(new Cat("招财猫", 8));报错
System.out.println("===使用泛型====");
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());

7.2 泛型介绍

泛型:广泛的类型,表示引用数据类型的类型,E ->Integer、String、Dog.....不可以是int....等基本数据类型

1):泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题

2):在类声明或实例化时只要指定好需要的具体的类型即可。ArrayList<Dog> arrayList

3):Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮

4):泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方
法的返回值的类型,或者是参数类型。

5):在编译期间,就确定 E 是什么类型

Person<Integer> person2 = new Person<Integer>("hahha");
//则Person类里面所有的E都是String了
class Person<E> {
E s ;
//E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
public Person(E s) {//E 也可以是参数类型
this.s = s;
}
public E f() {//返回类型使用 E
return s;
}
}

7.3 泛型的语法

interface 接口名<T>{}

class 类名<K,V>{}

1):其中T,K,V都不代表值,而是表示引用类型

2):任意字母都可以,常用T

3):泛型的实例化,要在类名后面指定类型参数的值(类型)

eg:lterator<Customer> iterator = customers.iterator();

4):在指定泛型具体类型后,可以传入该类型或者其子类类型

5):如果没有传入泛型类型,默认是Object,ArrayList arrayList = new ArrayList();等价 ArrayListarrayList = new ArrayList();

6):泛型的使用形式可以简写,例如ArrayList<Integer> list3 = new ArrayList<>(); 编译器会进行类型推断

7):exercise

public class Generic_ {
    public static void main(String[] args) {
        /**
         * 定义 Employee 类
         * 1) 该类包含:private 成员变量 name,sal,birthday,其中 birthday 为 MyDate 类的对象;
         * 2) 为每一个属性定义 getter, setter 方法;
         * 3) 重写 toString 方法输出 name, sal, birthday
         * 4) MyDate 类包含: private 成员变量 month,day,year;并为每一个属性定义 getter, setter 方法;
         * 5) 创建该类的 3 个对象,并把这些对象放入 ArrayList 集合中(ArrayList 需使用泛型来定义),对集合中的元素进
         行排序,并遍历输出:
         *
         * 排序方式: 调用 ArrayList 的 sort 方法 , * 传入 Comparator 对象[使用泛型],先按照 name 排序,如果 name 相同,则按生日日期的先后排序。【即:定制排序】
         */
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("tom", 20000, new MyDate(1980,12,11)));
        employees.add(new Employee("jack", 12000, new MyDate(2001,12,12)));
        employees.add(new Employee("tom", 50000, new MyDate(1980,12,10)));
        System.out.println(employees);
        Collections.sort(employees, new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                int i1= o1.getName().compareTo(o2.getName());
                if (i1!=0){
                    return i1;
                }
                return o1.getBirthday().compareTo(o2.getBirthday());
            }
        });
        System.out.println("排序后\n"+employees);
    }
}
class Employee{
    private String name;
    private double sal;
    private MyDate birthday;

    public Employee(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}
class MyDate implements Comparable<MyDate>{
    private int year;
    private int month ;
    private int day ;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return year +
                "-" + month +
                "-" + day;
    }
    @Override
    public int compareTo(MyDate o) {
        int yearMinus=year-o.getYear();
        int monthMinus=month-o.month;
        int dayMinus=day-o.day;
        if(yearMinus!=0){
            return yearMinus;
        }
        if(monthMinus!=0){
            return monthMinus;
        }
        return dayMinus;
    }
}

7.4 自定义泛型类

自定义泛型属性只能在泛型接口和泛型类中

1):基本语法

class 类名<T,R...>{//可以有多个泛型

成员

}

把这种称为自定义泛型类

2):普通成员可以使用泛型(属性、方法)

3):使用泛型的数组不能初始化(数组在new的时候不知道类型没办法开空间)

4):静态方法中不能使用类的泛型(静态跟类相关,类加载时对象还没有创建,JVM不知道静态是什么类型)

5):泛型类的类型,是在创建对象时指定的

6):如果在创建对象时没有指定类型,默认为Object

7.5 自定义接口

1):基本语法

interface 接口名<T,R...>{//可以有多个泛型

成员

}

2):静态成员不能使用泛型

3):泛型接口的类型在继承接口或者实现接口时确定

3):没有指定类型默认为Object

7.6 自定义泛型方法

1):基本语法

修饰符 <T,R...> 返回类型 方法名(参数列表){

}

2):泛型方法可以定义在普通类中,也可以定义在泛型类中

3):当泛型方法被调用时,传入参数,类型就会被确定

4):public void print(E e){}是使用了泛型不是泛型方法

5):泛型方法可以使用类声明的泛型,也可以使用方法中声明的泛型

class Fish<E>{
    E e;
    public <T> void print(T t,E e){
        
    };
    
}

7.7 泛型的继承和通配符

1):泛型不具备继承性

2):<?>:跟在有类型型参的类或接口后面,表示支持任意泛型类型,例如:List<?> e表示可以接受类型型参为任意的List

3):<? extends A>:支持A类以及A类的子类,规定了泛型的上限

4):<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

8 JUnit的使用

1):JUnit是一个java语言的单元测试框架

2):多数java的开发环境已经集成了JUnit作为单元测试的工具

3):在需要测试的方法前加@Test,点击绿色小箭头运行方法(光标放在对应的方法处快捷键也可以运行)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值