黑马程序员---集合-泛型、增强for、Set集合

来源:互联网 发布:互联主机销售系统源码 编辑:程序博客网 时间:2024/06/03 08:57

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

一、泛型
集合就像仓库,可以装任何的引用类型;因为它的add()方法接收的是Object类型的。对于集合类,看似功能比较强大,可以添加任何类型的引用。但取出的时候,也比较费事,我们以后使用集合类,经常是向集合中添加一种类型的引用;
在这个时候,Java为我们提供了一种语法功能:可以将一个集合,在定义时,同时定义这个集合中只能存放什么类型的元素。这种功能就叫:泛型
例如:我们需要定义一个只存储”字符串”的集合:

   ArrayList<String> list = new ArrayList<String>();   或   ArrayList<String> list = new ArrayList<>();(经常使用这种形式)   或   ArrayList<String> list = new ArrayList();

这里看个程序,使用泛型来存储字符串

import java.util.ArrayList;public class Demo {    public static void main(String[] args) {        //1.定义一个只能存储字符串的集合        ArrayList<String> strList = new ArrayList();        //2.填充元素        strList.add("aaa");        strList.add("bbb");        strList.add("ccc");        //strList.add(10);//编译错误,不能存储非String类型的数据。        //3.遍历        for(int i = 0;i < strList.size() ; i++){            String s = strList.get(i);//取出时,不需要再强转了,直接接收就可以            System.out.println(s);        }    }}

上面的程序使用泛型后,就不用担心存入的不是规定元素类型,这样使用泛型会给程序员带来几点好处,即:
A:把运行时期的问题提前到了编译期间
B:避免了强制类型转换
C:优化了程序设计,解决了黄色警告线

二、增强for循环
增强for循环又叫foreach循环,它的格式为:
for(数据类型 变量名:集合对象名/数组名){
//语句体
}
使用增强for循环的时候需要注意:
1.增强for不使用循环变量;
2.根据自己的需要,如果需要使用循环变量,那么就使用普通的for循环;如果不需要循环变量,只是简单的遍历一下集合或数组,那么使用增强for的语法会简洁许多。
3.增强for类似于迭代器,通过它对集合进行遍历时,仍然不能使用集合对象对集合内部进行修改,否则将抛出:并发修改异常:java.util.ConcurrentModificationException

import java.util.ArrayList;public class ForeachDemo {    public static void main(String[] args) {        ArrayList<String> strList = new ArrayList<>();        strList.add("aaa");        strList.add("bbb");        strList.add("ccc");        //之前遍历使用普通for        for(int i = 0;i < strList.size() ; i++){            String s = strList.get(i);            System.out.println(s);        }        System.out.println("********增强for循环*******");        //增强for        for(String s : strList){            System.out.println(s);        }        System.out.println("*******普通for循环遍历数组********");        int[] intArray = {432,4,24,32,54,36,54,7,65,64,4};        for(int i = 0;i < intArray.length ; i++){            System.out.println(intArray[i]);        }        System.out.println("*******增强for循环遍历数组*************");        for(int n : intArray){            System.out.println(n);        }    }}

普通for循环和增强for循环的效果是一样的,增强for循环的代码看山去简洁,易懂,没有冗余。但是如果要使用循环变量,那就只能用普通for循环了。

三、Set集合的特点
Set接口和List接口都是Collection接口的子类接口,List接口的特点是存储元素可以重复,是有序的。但是Set接口中的元素恰恰相反,即存储的元素没有重复的,是无序的。
下面的程序就证明了这两个特点:

import java.util.HashSet;import java.util.Set;public class Demo {    public static void main(String[] args) {        //1.实例化一个集合        Set<String> strSet = new HashSet<>();        //2.填充集合        strSet.add("aaa");        strSet.add("bbb");        strSet.add("ccc");        strSet.add("ddd");        //尝试存储重复元素:        strSet.add("aaa");        strSet.add("bbb");        //再添加一个新元素        strSet.add("eee");        //3.遍历集合        Object[] objArray = strSet.toArray();        for(Object o : objArray){            System.out.println(o);//取出时,跟存入的顺序是不一致的        }    }}

这段程序输出的结果是:
这里写图片描述
从程序的输出结果就可以看出Set结合的两个特点。

四、HashSet集合存储自定义对象
上面说到的不能存储重复元素,里面的机制是依靠equals()方法和hashCode()方法来实现的,所以为了保证元素的唯一性,需要重写hashCode()方法和equals()方法。这里我们用HashSet结合存储自定义对象Student,来看看怎么实现存储不重复的元素。

先看Student类的代码

public class Student {    private String name;    private int age;    public Student(String name, int age) {        super();        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 "Student [name=" + name + ", age=" + age + "]";    }    //重写了hashCode方法    public int hashCode(){        return 0;    }    //重写了equals方法    @Override    public boolean equals(Object o){        if(obj == null){            return false;        }        if(!(obj instanceof Student)){            return false;        }        Student stu = (Student)obj;        return this.name.equals(stu.getName()) && this.age == stu.getAge();    }}

再看看测试类的代码

import java.util.HashSet;public class Demo {    public static void main(String[] args) {        //1.实例化一个HashSet        HashSet<Student> stuSet = new HashSet<>();        //2.填充集合        stuSet.add(new Student("张三",20));        stuSet.add(new Student("李四",22));        stuSet.add(new Student("王五",24));        stuSet.add(new Student("赵六",26));        //存储重复元素;        stuSet.add(new Student("赵六",26));//在重写hashCode和equals()方法后,不能存入了        //3.遍历        for(Student stu : stuSet){            System.out.println(stu);        }    }}

打印的结果是:
这里写图片描述

五、LinkedHashSet类
哈希表保证元素的唯一性,链表保证元素的有序(取出时和存入的书序是一样的)。

import java.util.LinkedHashSet;public class Demo {    public static void main(String[] args) {        //1.实例化一个集合        LinkedHashSet<String> strSet = new LinkedHashSet<>();        //2.填充集合        strSet.add("aaa");        strSet.add("bbb");        strSet.add("ccc");        strSet.add("ddd");        //3.遍历        for(String s : strSet){            System.out.println(s);        }    }}

六、TreeSet
这个集合内部使用树的数据结构实现的,并且默认会对存入的元素进行比较并排序,这种排序有两种方式,是自然排序和比较器排序。
下面的例子就是这个特点:

import java.util.TreeSet;public class Demo {    public static void main(String[] args) {        //1.实例化一个TreeSet        TreeSet<Integer> set = new TreeSet<>();        //2.填充集合        set.add(88);//先隐式装箱。Set中存储的是Integer类型        set.add(20);        set.add(5);        set.add(75);        set.add(60);        set.add(50);        set.add(60);        set.add(290);        //3.打印        for(int n : set){            System.out.println(n);        }        System.out.println("*****字符串*********");        TreeSet<String> strSet = new TreeSet<>();        strSet.add("b");        strSet.add("d");        strSet.add("a");        strSet.add("c");        strSet.add("f");        strSet.add("e");        for(String s : strSet){            System.out.println(s);        }    }}

程序运行的结果是:
这里写图片描述

上面的程序存入的元素都是有比较功能的,如果存储自定义对象的数据了,那TreeSet就不会比较了,程序就会抛出错误,导致程序不能正常运行。
解决的办法有两个:
(1):实现Comparable接口,重写compareTo()方法。这个就是自然排序
(2):给出一个比较器,即实现Comparator接口,重写compareTo()方法。这个就是比较器排序

下面举个存储Student类型的数据的例子
Student类的程序:

public class Student implements Comparable {    private String name;    private int age;    public Student(String name, int age) {        super();        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 "Student [name=" + name + ", age=" + age + "]";    }    @Override    public int compareTo(Object o) {        Student stu = (Student)o;        int n = this.name.compareTo(stu.getName());        int n2 = (n == 0 ? this.age - stu.age : n);//如果name相同,再比较年龄        return n2;    }}

再看测试类中的代码

import java.util.TreeMap;import java.util.TreeSet;public class Demo {    public static void main(String[] args) {        TreeSet<Student> stuSet = new TreeSet<>();        stuSet.add(new Student("zhangsan",20));        stuSet.add(new Student("lisi",22));        stuSet.add(new Student("wangwu",24));        stuSet.add(new Student("zhaoliu",26));        stuSet.add(new Student("lisi",32));        TreeMap m;        for(Student stu : stuSet){            System.out.println(stu);        }    }}

程序运行的结果是:
这里写图片描述
从结果就可以看出,程序只要重写了compareTo()方法,就可以按照重写的规则排序存入的元素。
注意:存入的元素的比较排序默认是基于Unicode编码的,对中文是不支持的。

0 0
原创粉丝点击