Java学习Day08------泛型、Set集合、二叉树

泛型、Set集合、二叉树

  • 泛型
    • 泛型类
    • 泛型方法
    • 泛型接口
    • 类型通配符
  • Set集合
    • TreeSet
  • 二叉树
    • 二叉查找树
    • 平衡二叉树

泛型

(1)概念:表示集合中存储的数据类型
(2)好处:
  a)把运行时期的问题提前到了编译期间
  b)避免了强制类型转换(如果不添加泛型,集合中存储的数据是Object[]数组,在调用一些方法的时候就需要进行强制类型转换)
(3)使用位置
  类后面:成为泛型类
  方法申明上:泛型方法
  接口后面:泛型接口
(4)定义格式
  <类型> 类型可以用任意字母代表
(5)注意事项:
  对于泛型而言,属于编译时,编译时看左边,运行时看左边,看等号左边是谁,则优先使用谁

泛型类

(1)定义格式
  修饰符 class 类名<泛型类型>
  示例:

//泛型类
public class Box<SVIP> {
    //定义泛型
    private SVIP vip;
    public SVIP getVip() {
        return vip;
    }
    public void setVip(SVIP vip) {
        this.vip = vip;
    }
}

泛型方法

(1)定义格式:
  修饰符 <泛型类型> 返回值类型 方法名(类型 变量名){ }
  示例

public <T> void show(T t){
}

泛型接口

(1)定义格式
  修饰符 interface 接口名<泛型类型>{}
  示例:

public interface intel<T> {
}
//泛型接口  ---> 相当于是 List
public interface JieKou<SVIP> {
    //定义抽象方法
    public abstract void methodAbsract(SVIP vip);
}
//接口实现类  ---> 相当于是 ArrayList
public class ShiXianLei<SVIP> implements JieKou<SVIP>{
    @Override
    public void methodAbsract(SVIP vip) {
        System.out.println(vip);
        System.out.println(vip.getClass());
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        // (1). 创建实现类的对象,定义泛型是 String
        ShiXianLei<String> sxl1 = new ShiXianLei<>();
        sxl1.methodAbsract("Hello");
        System.out.println("----------");
        // (2). 创建实现类的对象, 定义泛型是 Float
        ShiXianLei<Float> sxl2 = new ShiXianLei<>();
        sxl2.methodAbsract(6.666F);
    }
}

类型通配符

(1) 类型通配符:
  ArrayList: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型, 但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
(2) 类型通配符上限:
  ArrayList: 它表示的类型是Number或者其子类型
(3) 类型通配符下限:
  ArrayList: 它表示的类型是Number或者其父类型
(4)示例:

前提条件:
    class Integer extends Number{ .... }
    class Number  extends Object{ .... }

    定义泛型的上限限定 extends
    ArrayList<? extends Number>    //如果这样写,表示哪些可以使用啊?  Number 和 Number 的子类。 (Number\Integer)
    
    定义泛型的下限限定 super
    ArrayList<? super Number>      //如果这样写,表示哪些可以使用啊?  Number 和 Number 的父类。 (Number\Object)

    例如: Java的底层代码 API 当中,有这样的实例。
    在 Java底层代码, 集合体系结构 Collection 当中,包含有一个方法:
    boolean addAll(Collection<? extends E> c);   //定义的是泛型的 上限限定。

(5)坑

//泛型通配符的练习题
public class Test {
    public static void main(String[] args) {
        //采用普通的方式创建对象
        ArrayList<String> list1 = new ArrayList<>();
        method(list1);   //...【2】ArrayList...
        System.out.println("-------");
        //采用多态的方式创建对象
        Collection<String> list2 = new ArrayList<>();
        method(list2);  //...【1】Collection...
        System.out.println("=========");
        Set<Integer> set1 = new HashSet<>();
        method(set1);  //...【3】Set...
        System.out.println("----");
        HashSet<Double> set2 = new HashSet<>();
        method(set2);  //...【4】HashSet...
    }

    //对于泛型而言,将运行时的问题,提前到了编译时。 ---> 泛型属于编译时。
    //多态是: 对于成员方法而言, 编译看左边,运行看右边。 --》因为方法有重写。
    //对于泛型而言,属于编译时。 编译看左边, 运行看左边。
    // 看等号的左边是谁,则优先使用谁。

    public static void method(Collection<?> param){
        System.out.println("...【1】Collection...");
    }
    public static void method(ArrayList<?> param){
        System.out.println("...【2】ArrayList...");
    }
    public static void method(Set<?> param){
        System.out.println("...【3】Set...");
    }
    public static void method(HashSet<?> param){
        System.out.println("...【4】HashSet...");
    }
}

Set集合

(1)分类
  HashSet:常用于去除重复
  TreeSet:常用于排序
(2)特点
  a) 无序:存放和取出的顺序可能不一致
  b) 无重复:不可以有重复的元素
  c) 无索引:没有带索引的方法

TreeSet

(1)特点
  a) 不包含重复元素
  b) 没有带索引的方法
  c) 可以按照规则进行排序
(2)注意事项
  a) 如果存储自定义类型数据,必须要制定比较规则
    aa) 自然排序,需要实现Comparable接口
      升序:this-o
      降序:o-this
    示例:

// 学生类
public class Student implements Comparable<Student> {
    private String name;
    private 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(Student student) {
        // 从小到大 this-student; 从大到小 student-this
        int result = this.age-student.age;
        // 如果年龄相同,需要按照姓名排
        result = (result==0)? this.name.compareTo(student.name):result;
        return result;
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        ts.add(new Student("zhangsan",19));
        ts.add(new Student("lisi",15));
        ts.add(new Student("wangwu",21));
        ts.add(new Student("zhaoliu",15));
        ts.forEach(student -> System.out.println(student));
    }
}

    bb) 比较器排序,不需要实现Comparable接口
      升序:o1-o2
      降序:o2-o1
    示例:

// 学生类
public class Student {
    private String name;
    private 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 +
                '}';
    }
}
// 测试类
public class Test {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student student, Student t1) {
                int result = student.getAge() - t1.getAge();
                result = result==0?student.getName().compareTo(t1.getName()):result;
                return result;
            }
        });
        ts.add(new Student("zhangsan",19));
        ts.add(new Student("lisi",15));
        ts.add(new Student("wangwu",21));
        ts.add(new Student("zhaoliu",19));
        ts.forEach(student -> System.out.println(student));
    }
}

二叉树

  二叉树只能有一个父节点,最多可以有两个子节点。普通的二叉树中数据混乱

二叉查找树

概述:由二叉树升级过来,数据在树中按顺序排列
(1)特点:对于每个节点来说,左子节点的数据小于自己,右子节点的数据大于自己
(2)好处:方便查找,查找的时候一次就能舍弃一边的数据
(3)缺点:添加数据的时候可能出现长短腿的问题,也就是左右子树的深度差距很大

平衡二叉树

概述:也就是树中所有节点的左右子树高度差都不超过1
(1)左旋:当右子树的节点过多的情况下,需要向左旋转。
(2)右旋:当左子树的节点过多的情况下,需要进行向右旋转。
(3)常见旋转
  a) 左子树的左子树添加节点(左左)
    直接整体右旋
  b) 右子树的右子树添加节点(右右)
    直接整体左旋
  c) 左子树的右子树添加节点(左右)
    先左子树部分左旋,然后整体右旋
    例子:

在 7 节点的左子树(2,4,5) 的右子树 (5) 添加节点 6
部分左旋,整体右旋

Java学习Day08------泛型、Set集合、二叉树_第1张图片

部分左旋,整体右旋。
(1) 部分左旋: 5节点,变成左子树的根节点。4节点 降级成为 左子树 的 左子树。
(2) 整体右旋: 5节点,变成根节点。7节点 降级成为右子树。 6节点 交给7节点的左子树。

  d) 右子树的左子树添加节点(右左)
    先右子树部分右旋,然后整体左旋
    例子:

在7节点的右子树(9,10,11)的右子树(9) 添加节点 8
部分右旋,整体左旋

Java学习Day08------泛型、Set集合、二叉树_第2张图片

部分右旋,整体左旋。
(1) 部分右旋: 9节点,变成右子树的根节点。10节点 降级成为 右子树 的 右子树。
(2) 整体左旋: 9节点, 变成根节点。7节点降级成为左子树。 8节点 交给7节点的右子树。

你可能感兴趣的:(JavaSE学习,java)