编程知识 cdmana.com

JavaSE学习笔记18:集合(四)

集合(四)

HashMap和Hashtable的区别

HashMap的key可以为null吗?value呢?都可以为空!

package se3.themap;

import java.util.HashMap;
import java.util.Map;

public class HashMapTest03 {
    public static void main(String[] args) {
        Map map = new HashMap();
        //HashMap集合允许key为null
        map.put(null,null);
        System.out.println(map.size());//1
        //key重复的话,value会覆盖
        map.put(null,100);
        System.out.println(map.size());//1
        //通过key获取value
        System.out.println(map.get(null));//100
    }
}

Hashtable的key可以为null吗?value呢?都不能为空!

package se3.themap;

import java.util.Hashtable;
import java.util.Map;

public class HashTableTest01 {
    public static void main(String[] args) {
        Map map = new Hashtable();
        map.put(null,"阿波");
        map.put(1,null);
    }
}
  1. Hashtable和HashMap一样,底层都是哈希表数据结构
  2. Hashtable方法都带有synchronized:线程安全的
  3. Hashtable的初始化容量是11,默认加载因子是0.75
  4. Hashtable的扩容:原容量*2再+1

Properties

​ 目前只需要掌握Properties属性类对象的相关方法即可

​ Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型

​ Properties被称为属性类对象

​ Properties是线程安全的

package se3.themap;

import java.util.Properties;

public class PropertiesTest01 {
    public static void main(String[] args) {
        //创建一个Properties对象
        Properties pro = new Properties();
        //需要掌握Properties的两个方法,一个存,一个取
        pro.setProperty("url","jdbc:mysql://localhost:3306/bjpowernode");
        pro.setProperty("driver","com.mysql.jdbc.Driver");
        pro.setProperty("username","root");
        pro.setProperty("password","123");
        //通过key获取value
        String url = pro.getProperty("url");
        String driver = pro.getProperty("driver");
        String username = pro.getProperty("username");
        String password = pro.getProperty("password");

        System.out.println(url);//jdbc:mysql://localhost:3306/bjpowernode
        System.out.println(driver);//com.mysql.jdbc.Driver
        System.out.println(username);//root
        System.out.println(password);//123
    }
}

TreeSet

  1. TreeSet集合底层实际上是一个TreeMap
  2. TreeMap集合底层是一个二叉树
  3. 放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了
  4. TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序,称为可排序集合。
package se3.set;

import java.util.TreeSet;

public class TreeSetTest02 {
    public static void main(String[] args) {
        //创建TreeSet集合
        TreeSet<String> ts = new TreeSet<>();
        //添加String元素
        ts.add("钱七");
        ts.add("张三");
        ts.add("赵六");
        ts.add("李四");
        ts.add("王五");
        //遍历
        for (String s : ts){
            //按照字典顺序,升序
            System.out.print(s + " ");
        }//张三 李四 王五 赵六 钱七
        System.out.println();

        TreeSet<Integer> ts2 = new TreeSet<>();
        ts2.add(100);
        ts2.add(200);
        ts2.add(900);
        ts2.add(800);
        ts2.add(600);
        ts2.add(10);
        for (Integer elt : ts2){
            //升序
            System.out.print(elt + " ");
        }//10 100 200 600 800 900
    }
}

关于自定义类型排序

对自定义的类型来说,TreeSet可以排序吗?不行

  1. 以下程序中对于Person类型来说,无法排序。因为没有指定Person对象之间的比较规则
  2. 谁大谁小并没有说明
  3. 出现异常的原因是:Person类没有实现java.lang.Comparable接口。
package se3.set;

import java.util.TreeSet;

public class TreeSetTest03 {
    public static void main(String[] args) {
        Person p1 = new Person(32);
        Person p2 = new Person(20);
        Person p3 = new Person(30);
        Person p4 = new Person(25);
        //添加元素
        TreeSet<Person> persons = new TreeSet<>();
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        //遍历
        for (Person p : persons){
            System.out.print(p + " ");
        }
        /**运行结果:
         * Exception in thread "main" java.lang.ClassCastException: se3.set.Person cannot be cast to java.lang.Comparable
         *     at java.util.TreeMap.compare(TreeMap.java:1294)
         *     at java.util.TreeMap.put(TreeMap.java:538)
         *     at java.util.TreeSet.add(TreeSet.java:255)
         *     at se3.set.TreeSetTest03.main(TreeSetTest03.java:18)
         */
    }
}
class Person{
    int age;
    public Person(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" + "age=" + age + '}';
    }
}

自定义规则后如下:

package se3.set;

import java.util.TreeSet;

public class TreeSetTest04 {
    public static void main(String[] args) {
        Person2 p1 = new Person2(32);
        Person2 p2 = new Person2(20);
        Person2 p3 = new Person2(30);
        Person2 p4 = new Person2(25);
        //添加元素
        TreeSet<Person2> persons = new TreeSet<>();
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        //遍历
        for (Person2 p : persons){
            System.out.println(p);
        }
        /**
         * 运行结果:
         * Person{age=20}
         * Person{age=25}
         * Person{age=30}
         * Person{age=32}
         */
    }
}
/*
放在TreeSet集合中元素需要实现java.lang.Comparable接口
并且实现CompareTo方法,equals可以不写
 */
class Person2 implements Comparable<Person2>{
    int age;
    public Person2(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person{" + "age=" + age + '}';
    }

    //需要在这个方法中编写比较的逻辑,或者说比较的方法,按什么进行比较
    //k.compareTo(t.key)
    //拿着参数k和集合中的每一个k进行比较,返回值可能是>0 <0 =0
    //比较规则是由程序员指定的,例如按照年龄升序或者降序
    @Override
    public int compareTo(Person2 p) {//p1.compareTO(p2)
        //this就是p1
        //p是p2
        //p1和p2比较的时候,就是this和p比较
        /*
        int age1 = this.age;
        int age2 = p.age;
        if(age1 == age2){
            return 0;
        } else if(age1 > age2){
            return 1;
        } else{
            return -1;
        }
        */
        //简写
        return this.age - p.age;
    }
}

关于比较规则

怎么写?先按照年龄升序,如果年龄一样再按照姓名升序,例子如下:

package se3.set;

import java.util.TreeSet;

//先按照年龄升序,如果年龄一样再按照姓名升序
public class TreeSetTest05 {
    public static void main(String[] args) {
        TreeSet<Vip> vips = new TreeSet<>();
        vips.add(new Vip("a阿波",20));
        vips.add(new Vip("b阿波",20));
        vips.add(new Vip("波波",18));
        vips.add(new Vip("小波",17));
        for (Vip vip : vips){
            System.out.println(vip);
        }
        /**
         * 输出结果:
         * Vip{name='小波', age=17}
         * Vip{name='波波', age=18}
         * Vip{name='a阿波', age=20}
         * Vip{name='b阿波', age=20}
         */
    }
}
class Vip implements Comparable<Vip>{
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Vip{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    /*
    compareTo方法的返回值很重要:
        返回0表示相同,value会覆盖
        返回>0,会继续在右子树上找【10-9=1,1>0的说明左边这个数字比较大,所以在右子树上找】
        返回<0,会继续在左子树上找
     */

    @Override
    public int compareTo(Vip v) {
        if(this.age == v.age){
            //年龄相同时按照名字排序
            //名字是String类型,可以直接比,调用compareTo完成比较
            return this.name.compareTo(v.name);
        } else {
            //年龄不一样
            return this.age - v.age;
        }
    }
}

自平衡二叉树数据结构

TreeSet/TreeM是自平衡二叉树,遵循左小右大原则存放(存放的时候要进行比较)

注意:存放的过程就是排序的过程,取出来就是自动按照大小顺序排列

100 200 50 60 80 120 140 130 135 180 666 40 55存放后如下图

遍历二叉树的时候有三种方式

  1. 前序遍历:根左右
  2. 中序遍历:左根右
  3. 后序遍历:左右根

TreeSet集合/TreeMap集合采用的是:中序遍历

Iterator迭代器采用的是中序遍历方式(左根右)

中序遍历

采用中序遍历取出:

40 50 55 60 80 100 120 140 130 135 180 200 666

比较器方式实现TreeSet排序

package se3.set;

import java.util.Comparator;
import java.util.TreeSet;
/*
TreeSet集合中元素可排序的第二种方式:使用比较器的方式
 */
public class TreeSetTest06 {
    public static void main(String[] args) {
        //创建TreeSet集合的时候,需要使用这个比较器
        //TreeSet<WuGui> wuGuis = new TreeSet<>();//这样不行,没有通过构造方法传递一个比较器进去
        //给构造方法传递一个比较器
        TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());
        wuGuis.add(new WuGui(1000));
        wuGuis.add(new WuGui(800));
        wuGuis.add(new WuGui(810));
        for (WuGui wuGui : wuGuis){
            System.out.println(wuGui);
        }
        /**
         * 输出结果:
         * 乌龟[age=800]
         * 乌龟[age=810]
         * 乌龟[age=1000]
         */
    }
}
//乌龟
class WuGui{
    int age;

    public WuGui(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "乌龟[" +
                "age=" + age +
                ']';
    }
}
//单独在这里编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的,Comparator是java.util包下的)
class WuGuiComparator implements Comparator<WuGui>{
    @Override
    public int compare(WuGui o1, WuGui o2) {
        //指定比较规则,按照年龄排序
        return o1.age - o2.age;
    }
}

匿名内部类方式实现TreeSet排序

package se3.set;

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetTest06 {
    public static void main(String[] args) {
        //TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());
        //使用匿名内部类的方式
        TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
            @Override
            public int compare(WuGui o1, WuGui o2) {
                return o1.age - o2.age;
            }
        });
        wuGuis.add(new WuGui(1000));
        wuGuis.add(new WuGui(800));
        wuGuis.add(new WuGui(810));
        for (WuGui wuGui : wuGuis){
            System.out.println(wuGui);
        }
        /**
         * 输出结果:
         * 乌龟[age=800]
         * 乌龟[age=810]
         * 乌龟[age=1000]
         */
    }
}
//乌龟
class WuGui{
    int age;

    public WuGui(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "乌龟[" +
                "age=" + age +
                ']';
    }
}

结论

放到TreeSet或者TreeMap集合key部分的元素要想做到排序,包括两种方式:

  1. 放在集合中元素实现java.lang.Comparable接口
  2. 在构造TreeSet或者TreeMap集合的时候给它传一个比较器对象

Comparable和Comparator怎么选择呢?

当比较规则不会发生改变的时候,或者说当比较规则只有1个的时候,建议使用Comparable接口。

如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。

Collections工具类

package se3.collection;

import java.util.*;
/*
java.util.Collection 集合接口
java.util.Collections 集合工具类,方便集合的操作。
 */
public class CollectionsTest01 {
    public static void main(String[] args) {
        //ArrayList集合不是线程安全的
        List<String> list = new ArrayList<>();
        //变成线程安全的
        Collections.synchronizedList(list);
        list.add("abf");
        list.add("abx");
        list.add("abc");
        list.add("abe");
        //排序
        Collections.sort(list);
        for (String s : list){
            System.out.print(s + "  ");
        }//abc  abe  abf  abx
        System.out.println();

        List<WuGui2> wuGui2s = new ArrayList<>();
        wuGui2s.add(new WuGui2(1000));
        wuGui2s.add(new WuGui2(8000));
        //注意:对List集合中元素排序,需要保证List集合中的元素实现Comparable接口
        Collections.sort(wuGui2s);
        for (WuGui2 wuGui2 : wuGui2s){
            System.out.println(wuGui2);
        }
        /*
        乌龟[age=1000]
        乌龟[age=8000]
        */

        //Set集合排序
        Set<String> set = new HashSet<>();
        set.add("king");
        set.add("kingsoft");
        set.add("king2");
        set.add("king1");
        //将Set集合转换成List集合
        List<String> mylist = new ArrayList<>(set);
        Collections.sort(mylist);
        for (String s : mylist){
            System.out.print(s + "  ");
        }//king  king1  king2  kingsoft 
    }
}
class WuGui2 implements Comparable<WuGui2>{
    int age;

    public WuGui2(int age) {
        this.age = age;
    }
    @Override
    public int compareTo(WuGui2 o) {
        return this.age - o.age;
    }
    @Override
    public String toString() {
        return "乌龟[" +
                "age=" + age +
                ']';
    }
}

版权声明
本文为[最爱琴女E]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/Sona-36D/p/13959494.html

Scroll to Top