第十二章 集合框架(三)

1.练习回顾

①定义商品类: 商品名字,价格;

②通过输入的方式创建5个商品;

③将商品添加到Set集合中,要求信息相同的商品不能重复添加;

④使用迭代器遍历商品信息。

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Set set = new HashSet();
        while(set.size()<5){
            System.out.println("请输入商品名称和商品价格:");
            Goods goods = new Goods(scanner.next(),scanner.nextDouble());
            if (set.contains(goods)){
                System.out.println("商品重复,请重新输入!");
                continue;
            }
            set.add(goods);
        }
        Iterator it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}

商品类:

public class Goods {
    private String name;
    double price;

    public Goods(String name, double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Goods goods = (Goods) o;
        return Double.compare(goods.price, price) == 0 && Objects.equals(name, goods.name);
    }

    @Override
    public int hashCode() {
        return this.name.hashCode() +Double.hashCode(this.price);
    }
    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

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

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

2. TreeSet

        TreeSet 基于TreeMap 实现;TreeSet可以实现有序集合,但是有序性需要通过比较器实现。

2.1 TreeSet特点

①有序;

②不重复;

③添加、删除、判断元素存在性的效率比较高;

④线程不安全。

2.2 TreeSet对元素进行排序的方式

① 如果是基本数据类型和String类型,无需其他操作,可以直接进行排序;

②对象类型元素排序,需要实现Comparable接口,并覆盖其compareTo方法;

③自己定义实现了Comparator接口的排序类,并将其传给TreeSet,实现自定义的排序规则。

实例①:

//基本数据类型,同类型才可以比较进而排序
public class Test {
    public static void main(String[] args) {
        Set set = new TreeSet();
        set.add("bc");
        set.add("ac");
        set.add("ab");

        Iterator it =set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}

 实例②:

//实现Comparable接口
public class Student implements Comparable{
    private String name;
    int age;
    public Student(){

    }

    public Student(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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //比较对象大小
    @Override
    public int compareTo(Object o) {
        //先判断类型是否一致
        if(!(o instanceof Student)){
            return 1;
        }
        Student s = (Student) o;
        if(this.age>s.age){
            return 1;
        }else if(this.age<s.age){
            return -1;
        }else {
            //年龄相等时,按姓名排序
            return this.name.compareTo(s.name);
        }
    }
}

实例③:

//自定义的比较器,用于特定对象的比较
public class MyComparator implements Comparator {
    @Override
    public int compare(Object o1, Object o2) {
        if(o1 instanceof Car && o2 instanceof Car){
            Car c1 = (Car) o1;
            Car c2 = (Car) o2;
            if(c1.price>c2.price){
                return 1;
            }else if(c1.price<c1.price){
                return -1;
            }else {
                return c1.brand.compareTo(c2.brand);
            }

        }
        return -1;
    }
}

3. LinkedHashSet

        LinkHashSet是一种有序的Set集合,其元素的存入和取出顺序是相同的。

public class Test {
    public static void main(String[] args) {
        Set set = new LinkedHashSet();
        set.add("c");
        set.add("d");
        set.add("a");
        set.add("a");
        set.add(10);
        set.add(9);
        System.out.println(set);
    }
}

 4. Map接口及其实现类

Map接口特点:

①以键值对方式存储数据(Collection是单值集合);

②键不能重复,键重复时,后面的数据会覆盖前面的数据;

③HashMap的键和值可以存储nll,HashTable不能存储null值;

④键值对数据无序。

返回类型方法描述
Objectget(Object key)根据key取得value
objectput(Object k,Object v)向集合中加入元素
voidclear()清除Map集合
booleanisEmpty()判断集合是否为空
booleancontainsKey(Object object)判断指定的key是否存在
booleancontainsValue(Object value)判断指定的value是否存在
SetkeySet()Map中所有的key的集合
objectremove(Object key)根据key删除对应的value
Collectionvalues()取出全部的value
int size()获得集合的长度

4.1 HashMap实现类

        HashMap实现了Map接口,拥有Map接口的基本特点;HashMap线程不安全,效率高;底层是由哈希表、链表和红黑树构成的。

public class Test {
    public static void main(String[] args) {
        //16:初始容量
        Map map = new HashMap(16);
        //put:存储数据
        map.put("name","小成");
        map.put("age","20");
        map.put("people",new People("小成",20));
        map.put("wen",18);
        //键重复时,后面的数据覆盖前面的
        map.put("wen",20);
        map.put(20,"wen");
        
        //判断是否为空
        System.out.println(map.isEmpty());
        
        System.out.println(map);
        //实际存储的元素个数
        System.out.println(map.size());
        //根据键获取值
        System.out.println(map.get("people"));
        //判断是否包含某个键
        System.out.println(map.containsKey(20));
        //返回map中键的集合,一个Set集合
        System.out.println(map.keySet());
        //返回map中值的集合,一个Collection集合
        System.out.println(map.values());
    }
}

 遍历集合:

        //①:遍历键的集合
        Set set = map.keySet();
        for (Object obj:set) {
            System.out.println(obj +"  "+map.get(obj));
        }
        
        //②:遍历键值对集合
        Set entrySet = map.entrySet();
        for (Object o:entrySet) {
            //Map.Entry:Map接口的子接口,表示一个键值对对象
            Map.Entry kv = (Map.Entry) o;
            System.out.println(kv.getKey()+"==="+kv.getValue());
        }

 4.2 HashMap底层原理

4.2.1 map.put(key,value)实现原理

①首先将k、v封装到Node对象中(节点);

②底层会调用k的hashCode()方法得出hash值;

③通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上,如果说下标对应位置上有链表,则会用这个k和链表上每个节点的k进行equals比较,如果所有的equals方法返回的都是false,则这个新的节点将被添加到链表的末尾,如果其中有一个equals返回true,则这个节点的value将会被覆盖。

 4.2.2 map.get(key) 实现原理

①先调用k的hashCode()方法计算哈希值,并通过哈希算法转换成数组的下标;

②通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上,如果这个位置上没有存储数据,则返回null;如果这个位置上有单向链表,则会将这个参数k和单链表上的每一个节点的k进行equals比较,如果都返回了false,则get方法返回null;如果有一个为true则该节点的value就是我们要找的value,并通过get方法返回这value。

 4.2.3 map的扩容原理

①当数组元素个数大于阈值(长度*0.75)时,数组扩容;

②当某个节点的链表超过8,并且数组长度小于64,此时不将链表转为树,而是进行扩容;

③当某个节点链表长度大于8,并且数组长度大于64,此时将链表转为红黑树。 

4.3 Hashtable

Hashtable也实现了Map接口,它的特点有:

①以键值对方式存储数据;

②键不能重复;

③数据无序;

④键和值都不能存储null;

⑤线程安全,效率低。

 4.4 泛型集合

泛型:对要管理的数据进行类型限定,方便数据的处理;

在往集合中存储数据的时候缺乏类型检查,不安全。

泛型:类型检查,省略了装箱和拆箱,效率高类型安全。

语法:

List<T>:E类型约束;

Set<T>:E类型约束;

Map<K,V>:K,V类型约束

 ①

public class Test {
    public static void main(String[] args) {
        List<People> list= new ArrayList<People>();
        //添加非People类型的数据直接报错
        //list.add("aaa");
        list.add(new People("张三",18));
        list.add(new People("李四",19));
        //遍历
        for (int i = 0; i < list.size(); i++) {
            People p = list.get(i);
            p.introduce();
        }

        for (People p:list) {
            p.introduce();
        }
        
    }
}
public class People {
    private String name;
    private int age;

    public People() {
    }

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

    //自我介绍
    public void introduce(){
        System.out.println(this.name+" "+this.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 "People{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Test2 {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("aaa");
        set.add("bbb");

        for (String s:set) {
            System.out.println(s);
        }

        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
    }
}

public class Test3 {
    public static void main(String[] args) {
        Map<String,People> map = new HashMap<>();
        map.put("张三",new People("张三",18));
        map.put("李四",new People("李四",19));
        Set<String> set = map.keySet();
        for (String s:set) {
            System.out.println(s+"  "+map.get(s));
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值