Java学习笔记day17-泛型-Set

Day17

泛型

泛型概述

泛型:是JDK5中引入的特性,它提供了编译时类型安全监测机制

泛型的好处:

  • 把运行时期的问题提前到了编译期
  • 避免了强制类型转换

泛型可以使用的地方:

  • 类后面,这样的类称为泛型类
  • 方法申明上,这样的方法称为泛型方法
  • 接口后面,这样的接口称为泛型接口

总结:

​ 如果一个类的后面有,表示这个类是一个泛型类;创建泛型类的对象时,必须要给这个泛型确定具体的数据类型。

泛型定义格式
  • <类型>:指定一种类型的格式。尖括号里可以任意书写,按照变量的定义规则即可。一般只写一个字母,比如
  • <类型1,类型2,…>:指定多种类型的格式,多种类型之间用逗号隔开。比如:<E,T> <Q,M>

定义一个泛型类FirstE.java

泛型类

定义格式:

  • 格式:修饰符 class 类名<类型>{}
  • 范例:public class Generic{}
public class FirstE<E> {
    private E element;

    public E getElement() {
        return element;
    }

    public void setElement(E element) {
        this.element = element;
    }
}

测试类

public class ETest {
    public static void main(String[] args) {
        FirstE<String> f1 = new FirstE<>();
        f1.setElement("自定义泛型");
        FirstE<Integer> f2 = new FirstE<>();
        f2.setElement(2233);
        System.out.println(f1.getElement()); //自定义泛型
        System.out.println(f2.getElement()); //2233
    }
}
泛型方法

定义格式:

  • 格式:修饰符<类型> 返回值类型 方法名(类型 变量名){}
  • 范例:public void show(T t){}
import java.util.ArrayList;

/*
    定义一个泛型方法,传递一个集合和四个元素,将元素添加到集合并返回
 */
public class EMethod {
    public static void main(String[] args) {
        ArrayList<String> list1 = addElement(new ArrayList<>(),"a","b","c","d");
        System.out.println(list1); //[a, b, c, d]
        ArrayList<Integer> list2 = addElement(new ArrayList<>(), 1, 2, 3, 4);
        System.out.println(list2); //[1, 2, 3, 4]
    }
    public static <T> ArrayList<T> addElement(ArrayList<T> list,T t1,T t2,T t3,T t4){
        list.add(t1);
        list.add(t2);
        list.add(t3);
        list.add(t4);
        return list;
    }
}
泛型接口

泛型接口的使用方式:

  • 实现类也不给泛型
  • 实现类确定具体的数据类型

泛型接口的定义格式:

  • 格式:修饰符 interface 接口名<类型>
  • 范例:public interface Generic{}
public class GenericityInterface {
    public static void main(String[] args) {
        GenericityImpl1<String> genericity = new GenericityImpl1<>();
        genericity.method("泛型接口...");

        GenericityImpl2 genericity2 = new GenericityImpl2();
        genericity2.method(2233);
    }
}

interface Genericity<E>{
    public abstract void method(E e);
}

class GenericityImpl1<E> implements Genericity<E>{
    @Override
    public void method(E e) {
        System.out.println(e); //泛型接口...
    }
}

class GenericityImpl2 implements Genericity<Integer>{
    @Override
    public void method(Integer integer) {
        System.out.println(integer); //2233
    }
}
类型通配符
  • 类型通配符:<?>
  • ArrayList<?>:表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
  • 但是并不能把元素添加得到ArrayList中了,获取出来的也是父类类型
  • 类型通配符上限:<?extends 类型>
  • 比如:ArrayList<?extends Number>:它表示Number类和所有子类
  • 类型通配符下限:<?super 类型>
import java.util.ArrayList;

public class Tongpei {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        ArrayList<Integer> list2 = new ArrayList<>();
        ArrayList<Number> list3 = new ArrayList<>();
        ArrayList<Object> list4 = new ArrayList<>();
        //printList(list1);
        //printList(list2);
        method1(list2);
        method1(list3);
        //method1(list4);不是Number的子类型不能传入
        method2(list4);
    }

    //表示传递进来的可以是Number类型,也可以是Number所有的子类型
    private static void method1(ArrayList<? extends Number> list) { }

    //表示传递进来的可以是Number类型,也可以是Number所有的父类型
    private static void method2(ArrayList<? super Number> list) { }

    private static void printList(ArrayList<?> list) { }
}

Set

set集合特点
  • 可以去除重复
  • 存取顺序不一致
  • 没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取、删除Set集合里面的元素
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

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

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

运行结果:
Java学习笔记day17-泛型-Set

TreeSet集合特点
  • 不包含重复元素的集合
  • 没有带索引的方法
  • 可以将元素按照规则进行排序
自然排序原理
  • 若返回值为负数,表示当前存入的元素是较小值,存左边
  • 若返回值为0,表示当前存入的元素跟集合中元素重复了,不存
  • 若返回值为正数,表示当前存入的元素是较大值,存右边

示例:

public class Student implements Comparable<Student> {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", 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;
    }

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

    public Student() {
    }

    @Override
    public int compareTo(Student o) {
        //按照年龄进行排序
        //this表示当前待存入的age,o表示集合中已存入的age,若有多个则依次进行比较
        int i = this.age - o.age;
        return i;
    }
}

测试类:

import java.util.TreeSet;

public class TreeSetTest {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        Student st1 = new Student("玲",13);
        Student st2 = new Student("七宝",7);
        Student st3 = new Student("戈薇",18);
        ts.add(st1);
        ts.add(st2);
        ts.add(st3);
        System.out.println(ts);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

案例:按照年龄排序

​ 按照年龄从小到大排序,如果年龄一样,则按照姓名首字母排序,如果姓名和年龄一样,才认为是同一个学生对象,不存入;

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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", 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 int compareTo(Student o) {
        int result = this.age - o.age;
        //三目运算,若年龄一样按姓名排
        result = result == 0 ? this.name.compareTo(o.name) : result;
        return result;
    }
}
import java.util.TreeSet;

public class StudentTest {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<>();
        Student st1 = new Student("岚岚",18);
        Student st2 = new Student("图图",11);
        Student st3 = new Student("泡泡",11);
        Student st4 = new Student("飞飞",16);
        Student st5 = new Student("飞飞",16);
        ts.add(st1);
        ts.add(st2);
        ts.add(st3);
        ts.add(st4);
        ts.add(st5);
        System.out.println(ts);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

比较器排序Comparator的使用
  • TreeSet的带构造方法使用的是比较器排序对元素进行排序的
  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
  • 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

练习:

自定义Teacher老师类,属性为姓名和年龄,请按照年龄排序,如果年龄一样,则按照姓名进行排序,姓名都是用英文字母表示;

public class Teacher {
    private String name;
    private int age;

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

    public Teacher() {
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", 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;
    }
}
import java.util.Comparator;
import java.util.TreeSet;

public class TeacherTest {
    public static void main(String[] args) {
        //匿名内部类
        TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
            @Override
            public int compare(Teacher o1, Teacher o2) {
                int result = o1.getAge() - o2.getAge();
                result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
                return result;
            }
        });
        Teacher t1 = new Teacher("make",24);
        Teacher t2 = new Teacher("rose",23);
        Teacher t3 = new Teacher("jack",24);
        Teacher t4 = new Teacher("tom",21);
        ts.add(t1);
        ts.add(t2);
        ts.add(t3);
        ts.add(t4);
        System.out.println(ts);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

补充:中文字符串排序
Java学习笔记day17-泛型-Set

两种比较方式小结
  • 自然排序:自定义实现类接口Comparable接口,重写compareTo方法,根据返回值进行排序
  • 比较器排序:创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
  • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,使用比较器排序
案例:按照字符串长短排序

自行选择比较器排序和自然排序两种方式;存入四个字符串,“c”,“ab”,“df”,“qwem”,按照长度排序,如果一样长则按照首字母排序;

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

public class AnliTest {
    public static void main(String[] args) {
        //由于String的原码已经重写过了Comparable接口里的方法,所以,只能用比较器排序
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int result = o1.length() - o2.length();
                result = result == 0 ? o1.compareTo(o2) : result;
                return result;
            }
        });
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwem");
        System.out.println(ts);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

练习1

已知数组信息如下:{2.2,5.5,6.6,2.2,8.8,1.1,2.2,8.8,5.5,2.2,6.6},请使用代码找出上面数组中的所有的数据,要求重复的数据只能保留一份;

import java.util.HashSet;

public class Lian1 {
    public static void main(String[] args) {
        double[] arr = {2.2,5.5,6.6,2.2,8.8,1.1,2.2,8.8,5.5,2.2,6.6};
        //将数组中的元素存入set集合,会自动去除重复的部分
        HashSet<Double> hs = new HashSet<>();
        for (double v : arr) {
            hs.add(v);
        }
        System.out.println(hs);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

练习2

​ 随机生成8个不重复的10至20之间的随机数并保存Set集合中,然后打印出集合中所有的数据;使用TreeSet集合实现;

import java.util.Random;
import java.util.TreeSet;

public class Lian2 {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        Random r = new Random();
        //set集合中不会存储重复的数
        //ts中有8个数的时候不满足<8,结束循环
        while (ts.size()<8){
            ts.add(r.nextInt(11)+10);
        }
        System.out.println(ts);
    }
}

运行结果:
Java学习笔记day17-泛型-Set

练习3

键盘输入3本书按照价格从低到高排序后输出,如果价格相同则按照书名的自然顺序排序;

要求

  1. 书以对象形式存在,包含书名和价格(int类型)两个属性;
  2. 要求即使直接打印书对象的时候,也能看到书的名称和价格,而不是书对象的地址值;
  3. 分别使用自然排序和比较器排序实现效果;

自然排序方式(在JavaBean类中实现Comparable)

public class Book implements Comparable<Book>{
    private String name;
    private int price;

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

    public String getName() {
        return name;
    }

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

    public int getPrice() {
        return price;
    }

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

    public Book(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public Book() {
    }

    @Override
    public int compareTo(Book o) {
        //主要条件
        int result = this.price - o.price;
        //次要条件
        return result == 0 ? this.name.compareTo(o.name) : result;
    }
}

测试类:
import java.util.Scanner;
import java.util.TreeSet;

public class BookTest {
    public static void main(String[] args) {
        TreeSet<Book> ts = new TreeSet<>();
        Scanner sc = new Scanner(System.in);
        int i = 1;
        while (true){
            System.out.println("请输入第"+i+"本书的书名:");
            String name = sc.next();
            System.out.println("请输入第"+i+"本书的价格(整数):");
            int price = sc.nextInt();
            Book b = new Book(name,price);
            ts.add(b);
            i++;
            System.out.println("输入1继续添加,其他数字则结束添加");
            int ch = sc.nextInt();
            if(ch!=1){
                break;
            }
        }
        System.out.println("你一共添加了"+ts.size()+"本书,分别是");
        for (Book book : ts) {
            System.out.println(book);
        }
    }
}

比较器方式(不用实现接口)

public class Book{
    private String name;
    private int price;

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

    public String getName() {
        return name;
    }

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

    public int getPrice() {
        return price;
    }

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

    public Book(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public Book() {
    }
}

测试类:
import java.util.Scanner;
import java.util.TreeSet;

public class BookTest {
    public static void main(String[] args) {
        TreeSet<Book> ts = new TreeSet<Book>((b1,b2)->{
            //主要条件
            int result = b1.getPrice()-b2.getPrice();
            //次要条件
            return result == 0 ? b1.getName().compareTo(b2.getName()) : result;
        });
        Scanner sc = new Scanner(System.in);
        int i = 1;
        while (true){
            System.out.println("请输入第"+i+"本书的书名:");
            String name = sc.next();
            System.out.println("请输入第"+i+"本书的价格(整数):");
            int price = sc.nextInt();
            Book b = new Book(name,price);
            ts.add(b);
            i++;
            System.out.println("输入1继续添加,其他数字则结束添加");
            int ch = sc.nextInt();
            if(ch!=1){
                break;
            }
        }
        System.out.println("你一共添加了"+ts.size()+"本书,分别是");
        for (Book book : ts) {
            System.out.println(book);
        }
    }
}

运行结果:
Java学习笔记day17-泛型-Set

上一篇:Laravel 5.8 做个知乎 14 —— 用户关注


下一篇:Go定时器--Timer