泛型 【了解】
什么是泛型
JDK5.0的新特性(增强for、自动拆装箱、泛型)
泛型是一种未知的(x)广泛的类型,可以表示任意的引用类型,你想让它是什么类型就可以是什么类型。
E -> String
E -> Integer

    * 泛型中传递的数据类型只能是引用数据类型

泛型的好处
    是编译时期的类型检查的安全机制
    泛型只在编译时期有效,编译之后泛型就没有了(泛型的擦除)

    1、可以将可能出现的问题提前解决
        运行时期可能会有类型转换异常
        提前到了编译时期

    2、省去了强转的麻烦,简化代码块


    以后我们在使用集合的时候都需要加上泛型


自定义泛型类
    格式
        public class 类名<泛型变量> {

        }

        泛型变量:一般习惯上使用英文大写
                可以一个字母组成,也可以是多个字母组成     <E> <T> <M>  <HELLO> <TYPE> <WORLD>
                可以使用一个变量,也可以使用多个变量       <K,V>


    泛型变量的使用
        在类中只要是可以使用数据类型的地方都可以使用泛型变量
        可以使用在成员变量上
            当做数据类型使用
        可以使用在成员方法上
            当做参数类型
            返回值类型
            在方法体内部当做类型

    什么时候确定泛型类的实际类型
        在创建对象的时候确定实际类型

自定义泛型方法
    格式
        修饰符 <泛型变量> 返回值类型 方法名(参数列表) {

        }

    泛型变量的使用
        只能在方法上以及方法内使用泛型变量,只要是用到数据类型的地方都可以使用泛型变量
        当做参数类型
        返回值类型
        在方法体内部当做类型

    什么时候确定泛型方法的实际类型
        在调用方法的时候确定实际类型

自定义泛型接口
    格式
        public interface 接口名<泛型变量> {

        }

        泛型变量:一般习惯上使用英文大写
                可以一个字母组成,也可以是多个字母组成     <E> <T> <M>  <HELLO> <TYPE> <WORLD>
                可以使用一个变量,也可以使用多个变量       <K,V>


    泛型变量的使用
        在接口中只要是可以使用数据类型的地方都可以使用泛型变量
        可以使用在方法(抽象方法或者非抽象方法)上
            当做参数类型
            返回值类型
            在方法体内部当做类型

        常量的类型不能使用泛型变量替代,接口中的常量是static修饰。


    什么时候确定泛型类的实际类型
        在创建实现类对象的时候确定实际类型
            public class GenericityImpl1<E> implements Genericity<E>{}
            GenericityImpl1<String> genericity = new GenericityImpl1<>();

        一个类在实现接口的时候确定实际类型
            public class GenericityImpl2 implements  Genericity<Integer> {
            }

        一个接口在继承该接口的时候确定实际类型
            interface A extends Genericity<String> {}
           ...

泛型通配符
    <?>

    <? extends E>:上限限定,只能指定类型或者其子类
    <? super E>:下限限定,只能是指定类型或者其父类

Set集合
特点:
不保证存取有序
无索引
不能存储重复元素

TreeSet               【了解】
    自然排序
        让集合元素对象所在的类实现Comparable接口,重写compareTo方法

        排序的规则就定义在compareTo方法中:
            1、方法的返回值,返回int类型的值,取值
                正数:存放的在右边(后面、下面)
                0:不存,去除掉
                负数:存放在左边(前面、上面)


            2、方法中的两个对象 this o
                this:当前要存储的元素
                o:已经存储到集合中的元素

                this - o 升序
                o - this 降序



    比较器排序
        让TreeSet容器具有排序的规则,将一个Comparator接口的实现类当做TreeSet的构造方法参数
        传递到TreeSet中
        TreeSet(Comparator<? super E> comparator)

        Comparator接口,重写compare方法

        排序的规则就定义在compare方法中:
            1、方法的返回值,返回int类型的值,取值
                正数:存放的在右边(后面、下面)
                0:不存,去除掉
                负数:存放在左边(前面、上面)


            2、方法中的两个对象 o1 o2
                o1:当前要存储的元素
                o2:已经存储到集合中的元素

                o1 - o2 升序
                o2 - o1 降序

                int compare(T o1, T o2);

    不管使用哪种方式都可以让TreeSet进行排序,如果这两种方式一种都没有选择,那么TreeSet排序就会报错。
    如果是JDK提供的类(Integer、String)
        一般都默认实现了自然排序规则,我们不需要设置任何的规则也可以正常排序
        但是如果我们不想要默认的自然排序规则,这时就选择比较器排序规则,这时两种排序规则
        同时存在,比较器排序规则会覆盖自然排序规则

    如果是我们自定义的类
        两种方式随便选择一种,你熟悉哪种就使用哪种。