栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

学习大数据的第22天——深入了解泛型、集合(Set、LinkedHashSet、TreeSet)以及一些小的知识点

学习大数据的第22天——深入了解泛型、集合(Set、LinkedHashSet、TreeSet)以及一些小的知识点

学习大数据的第22天——深入了解泛型、集合(Set、linkedHashSet、TreeSet)以及一些小的知识点 泛型的简述

泛型通配符
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
向下限定,E及其子类
? super E
向上限定,E及其父类

//任意类型,如果没有明确,那么就是Object以及任意的java类了
ArrayList list4 = new ArrayList();

//? extends E 向下限定,E及其子类
        ArrayList list7 = new ArrayList();
        
//? super E 向下限定,E及其父类
        ArrayList list11 = new ArrayList();

泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:泛型类型必须是引用类型

这里的<>里面的内容仅仅表示的使一种参数数据类型,参数类型是一种变量

泛型方法
把泛型定义再方法上
public <泛型类型> 返回类型 方法名(泛型类型.)

泛型接口
把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>

泛型类的测试类
public class GenericTool1{
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}
泛型方法的测试类
public  void show(F f){
        System.out.println(f);
    }
泛型接口的测试类
public interface GenericTool3 {
    public abstract void show(W w);
}
如果想要调用泛型接口,得重新定义一个类去实现接口的方法
public class GenericTool3Impl implements GenericTool3 {

    @Override
    public void show(W w) {
        System.out.println(w);
    }

}
可变参数的概述

定义方法的时候不知道定义多少参数

格式
修饰符 返回值类型 方法名(数据类型…变量名)
注意
这里的变量其实是一个数组
如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个

Arrays工具类中的一个方法
public static List asList(T… a)

public static void sum(String name, int... ints) {
        int sum = 0;
        for (int i : ints) {
            sum += i;
        }
        System.out.println(name + "学生的总成绩为:" + sum);
    }
增强for循环

JDK1.5之后出现的特性;
到目前为止,学过哪些知识使JDK1.5之后出现的?
泛型,增强for,包装类,Scanner,枚举

增强for循环概述:简化数组和Collection集合的遍历

语句定义格式:
for(元素数据类型 变量名(自定义) : 数组或者Collection集合) {
使用变量即可,该变量就是元素
}
好处:简化遍历

for(String string : strings){
            System.out.println(string);
        }
Set集合

Set集合:元素是唯一的,并且元素的顺序是无序的集合
在Set集合中存储的元素为什么不会有重复的呢?

当发现不明白的地方,可以追溯源码

总结:
HashSet中的add的方法
先比较添加元素的hash值,如果hash值一样,则判断equals方法,如果相等则说明元素相同,不添加。

Set接口,HashSet中add方法中源码分析
HashSet重写Set中的add方法:

//先将存入元素的哈希值与该位置上的元素的哈希值进行比较
//如果哈希值都不一样,继续走判断instanceof
//如果哈希值都一样,会调用元素的equals(k)方法进行比较
//如果equals(k)方法比较的结果是false的话,继续向下执行最终会将元素添加到集合中或者不添加
//如果equals(k)方法比较的结果是true的话,表示哈希值和内容都一样,表示元素重复了
//就覆盖,从现象上来看,其实就是不赋值
//说到这里,我们就已经知道HashSet中add()方法实际上与hashCode()方法和equals()方法有关
//集合中会不会去重取决于元素类有没有重写hashCode()方法和equals()方法
linkedHashSet

public class HashSet implements Set
public class linkedHashSet extends HashSet implements Set,

linkedHashSet:
1、底层数据结构是哈希表和链表
2、哈希表保证元素的唯一
3、链表保证了元素的有序(存储和取出的顺序一致)
4、线程不安全,效率高

集合的小练习: 练习一:获取10个1-20之间的随机数,要求不能重复

分析:
1、由于我们不确定获取随机数的次数,长度不好确定,所以我们选择集合
2、随机数生成的方式:Random类:nextInt(int num): 左闭右开

public class RandomTest {
    public static void main(String[] args) {
        //使用 ArrayList来进行存储
//        //1、创建随机数对象
//        Random random = new Random();
//        //2、创建集合对象存储随机数
//        ArrayList list = new ArrayList<>();
//
//        int count = 0;
//
//        while (count < 10) {
//            //生成随机数
//            int number = random.nextInt(20) + 1;
//            if (!list.contains(number)) {
//                list.add(number);
//                count++;
//            }
//        }
//        System.out.println(list);

        //使用Set集合进行存储
        Random random = new Random();

        Set list = new HashSet<>();

        while (list.size() < 10) {
            int number = random.nextInt(20) + 1;
            list.add(number);
        }
        System.out.println(list);

    }
}
练习二:键盘录入 多个 数据,以0结束 ,要求再控制台输出这多个数据中

分析:

1、由于不知道输入多少查看i。所以用while循环进行输入
2、用集合存储数据
3、toArray()
4、Arrays.sort()
5、取最后一个元素就是最大值

public class ListTest {
    public static void main(String[] args) {
        //创建键盘录入对象
        Scanner scanner = new Scanner(System.in);

        //创建集合对象
        ArrayList list = new ArrayList<>();

        boolean flag = true;
        while (flag) {
            int number = scanner.nextInt();
            if (number == 0) {
                flag = false;
                System.out.println("数据录入完毕!!");
            } else {
                list.add(number);
            }
        }

        //将集合转换为数组
        Object[] obj = list.toArray();
        Arrays.sort(obj);
        System.out.println("最大值为:" + obj[obj.length - 1]);

    }
}
练习3:用Set集合存储学生对象(当学生的姓名和年龄都一样的时候,判定是同一个学生)
public class SetDemo2 {
    public static void main(String[] args) {
        //创建集合对象
        Set student2s = new HashSet<>();

        //创建学生对象
        Student2 s1 = new Student2("明旺", 18);
        Student2 s2 = new Student2("王宇", 17);
        Student2 s3 = new Student2("周家祥", 19);
        Student2 s4 = new Student2("明旺", 18);

        //将学生对象添加到集合中
        student2s.add(s1);
        student2s.add(s2);
        student2s.add(s3);
        student2s.add(s4);

        for(Student2 student2 : student2s){
            System.out.println(student2);
        }


    }
}
练习4:了解静态导入是什么?

静态导入:
语句定义格式:import static 包名…类名.方法名;
可以直接导入到方法级别

注意事项:
1、方法必须是静态的

import static java.lang.Math.abs;
import static java.lang.Math.pow;

import static com.shujia.yl.day19.StaticClass.fun;
import static com.shujia.yl.day19.StaticClass.show;

class StaticClass {

    public static void fun(){
        System.out.println("数加科技nb!");
    }

    public static void show(String s){
        System.out.println(s);
    }
}

public class StaticimportDemo {
    public static void main(String[] args) {
        //Math
        System.out.println(Math.abs(-100));
        System.out.println(Math.pow(2, 3));
        System.out.println(Math.max(100, 200));

        //有没有什么方法,不同写类名,直接写方法名
//        System.out.println(abs(-200);

        //这时候需要静态导入的技术
        System.out.println(abs(-200));
        System.out.println(abs(-200));
        System.out.println(pow(2, 4));
        fun();
        show("spark");
        //如果此时我就是想使用静态导入的方法,怎么办?
        StaticClass.show("flink");
        //将前缀路径写完整
        com.shujia.yl.day19.StaticClass.show("flink");
        //当静态导入的方法名与本类中的方法名冲突的时候,我们发现,直接通过类名调用的方式会更加简单
        //所以根据实际情况,选择使用静态导入
    }

    public static void show(String s) {
        System.out.println("这是在StaticimportDemo类中的show方法" + s);
    }
}
练习5:集合的嵌套集合

集合的嵌套遍历
需求:目前,数加学院有十五期,十六期。每一期有很多学生,每个学生都是一个学生对象
可以用一个集合表示一个班的学生
十五期的学生:ArrayList classList15;
十六期的学生:ArrayList classList16;
无论是十五也好还是十六期,都是属于数加学院的班级
数加学院本身也可以通过集合表示:ArrayList shujia;

这样的现象叫做集合嵌套

public class ListQianTaoTest {
    public static void main(String[] args) {
        //定义一个十五期的班级集合
        ArrayList classList15 = new ArrayList<>();
        //定义一个十六期的班级集合
        ArrayList classList16 = new ArrayList<>();
        //定义一个数加学院的集合
        ArrayList> shujia = new ArrayList<>();

        //将十五期和十六期添加到shujia集合中
        shujia.add(classList15);
        shujia.add(classList16);

        //创建十五期的学生对象
        Student s1 = new Student("小五", 18);
        Student s2 = new Student("小六", 17);
        Student s3 = new Student("小七", 16);
        Student s4 = new Student("小八", 20);
        //创建十六期的学生对象
        Student s11 = new Student("小三", 18);
        Student s12 = new Student("小四", 17);
        Student s13 = new Student("小二", 19);
        Student s14 = new Student("老大", 16);

        //将15期的学生对象添加到十五集合中
        classList15.add(s1);
        classList15.add(s2);
        classList15.add(s3);
        classList15.add(s4);

        //将16期的学生对象添加到十六集合中
        classList16.add(s11);
        classList16.add(s12);
        classList16.add(s13);
        classList16.add(s14);

        //遍历
        //增强for循环遍历
//        for(ArrayList clazz : shujia){
//            for(Student s : clazz){
//                System.out.println(s);
//            }
//        }

        //普通for循环遍历
//        for (int i = 0; i < shujia.size(); i++) {
//            if (i == 0) {
//                System.out.println("=============十五期==============");
//                for (int j = 0; j < shujia.get(i).size(); j++) {
//                    Student student = shujia.get(i).get(i);
//                    System.out.println(student);
//
//                }
//            } else if (i == 1) {
//                System.out.println("=============十六期==============");
//                for (int j = 0; j < shujia.get(i).size(); j++) {
//                    Student student = shujia.get(i).get(i);
//                    System.out.println(student);
//
//                }
//            }
//        }

        System.out.println("========================================================");
        Iterator> iterator = shujia.iterator();
        while(iterator.hasNext()){
            ArrayList clazz = iterator.next();
            Iterator iterator1 = clazz.iterator();
            while(iterator1.hasNext()){
                Student student = iterator1.next();
                System.out.println(student);
            }
        }


    }
}
TreeSet集合

TreeSet:元素唯一,元素可以按照某种规则进行排序
两种排序方式:
自然排序
比较器排序

A NavigableSet实现基于TreeMap的元件使用其有序natural ordering ,或由Comparator集合创建时提供,这取决于所使用的构造方法。

为什么会进行去重以及排序呢?怎么排序呢?看源码。

TreeSet中add()源码分析
public abstract class AbstractCollection implements Collection{}

public abstract class AbstractSet extends AbstractCollection implements Set{}

public class TreeSet extends AbstractSet implements NavigableSet{
    private transient NavigableMap m;
    private static final Object PRESENT = new Object();

    TreeSet(NavigableMap m) {
            this.m = m;
    }

    public TreeSet() {
            this(new TreeMap());
    }

    public boolean add(E e) {
            //E -- Integer
            //e -- 20
            return m.put(e, PRESENT)==null;
    }
}


public class TreeMap extends AbstractMap implements NavigableMap{
    private transient Entry root;

    public TreeMap() {
            comparator = null;
    }


    public V put(K key, V value) {
        //key -- 20,18
        //value -- new Object()
        Entry t = root;

        //判断根有没有元素,如果没有根,把当前元素值作为根结点。
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }

        int cmp; //0
        Entry parent; //null
        // split comparator and comparable paths
        //由于我们使用的是无参构造方法,comparator的值是null
        Comparator cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            //key -- 18
            if (key == null)
                throw new NullPointerException();
            @SuppressWarnings("unchecked")
                //向下转型
                //要想这里可以顺利进行向下转型,元素的数据类型必须要实现Comparable接口
                Comparable k = (Comparable) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
}

如果TreeSet泛型是个自定义的引用类型,则会发生类型转换错误ClassCastException

按照正常的写法,我们一运行就报错了
java.lang.ClassCastException:类转换异常
由于我们这里TreeSet创建的时候使用的是无参构造构造方法,走的是自然排序
而这里底层源码中有一步是向下转型的
Comparable k = (Comparable) key;
报错了
原因是我们Student3类没有实现Comparable接口,无法进行向下转型,所以报错了。

Student3类:
public class Student3 implements Comparable {
    private String name;
    private int age;

    public Student3() {
    }

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

    @Override
    public int compareTo(Student3 student3) {
        //这里返回什么,应该是根据我们自己定义的规则来排序
        //比如说我想在去重的前提下,按照年龄进行排序。
//        return this.age - o.age;

        //年龄一样,姓名不一定一样
        //这里要区主次条件(主要条件是业务明确给出的,次要条件是我们自己分析得出的)
        int i = this.age - student3.age;
        //判断姓名是否一样(三目运算符)
        int i2 = i == 0 ? this.name.compareTo(student3.name) : i;
        return i2;
    }
}
public class TreeSetDemo2 {
    public static void main(String[] args) {
        //创建TreeSet集合
        TreeSet set = new TreeSet<>();

        //创建学生对象
        Student3 s1 = new Student3("theshy", 20);
        Student3 s2 = new Student3("xiaohu", 24);
        Student3 s3 = new Student3("uzi", 25);
        Student3 s4 = new Student3("卡萨", 22);
        Student3 s5 = new Student3("rookie", 23);
        Student3 s6 = new Student3("姿态", 21);
        Student3 s7 = new Student3("faker", 25);
        Student3 s8 = new Student3("xiaohu", 24);

        //将学生对象添加到集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);
        set.add(s7);
        set.add(s8);

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

    }
}
TreeSet自然排序小练习: Student4类:
public class Student4 implements Comparable {

    private String name;
    private int age;

    public Student4() {
    }

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

    @Override
    public int compareTo(Student4 o) {
        int i = this.name.length() - o.name.length();
        int i1 = i == 0 ? (this.name.compareTo(o.name)) : i;
        return i1;
    }
}

import java.util.TreeSet;

public class TreeSetDemo3 {
    public static void main(String[] args) {

        //创建TreeSet集合对象
        TreeSet set = new TreeSet<>();

        //创建学生对象
        Student4 s1 = new Student4("theshy", 20);
        Student4 s2 = new Student4("xiaohu", 24);
        Student4 s3 = new Student4("uzi", 25);
        Student4 s4 = new Student4("卡萨", 22);
        Student4 s5 = new Student4("rookie", 23);
        Student4 s6 = new Student4("姿态", 21);
        Student4 s7 = new Student4("faker", 25);
        Student4 s8 = new Student4("xiaohu", 24);

        //将学生对象添加到集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);
        set.add(s7);
        set.add(s8);

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

    }
}

比较器排序
利用TreeSet创建对象时的带参数的构造方法来进行比较器排序
TreeSet(Comparator comparator)
构造一个新的,空的树集,根据指定的比较器进行排序。

可以自定义一个比较器,也可以使用 匿名内部类来实现比较器排序 自定义比较器:
import java.util.Comparator;

public class MyComparator implements Comparator {

    @Override
    public int compare(Student5 o1, Student5 o2) {
        int i = o1.getName().length() - o2.getName().length();

        //如果长度一样,比较内容
        int i1 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
        //姓名内容一样,年龄的大小不一定一样
        int i2 = i1 == 0 ? o1.getAge() - o2.getAge() : i1;
        return i2;
    }
}
public class TreeSetDemo4 {
    public static void main(String[] args) {
//        MyComparator myComparator = new MyComparator();
//        //创建集合对象
//        TreeSet set = new TreeSet<>(myComparator);

        //也可以通过匿名内部类的形式去使用比较器
        TreeSet set = new TreeSet<>(new Comparator() {
            @Override
            public int compare(Student5 o1, Student5 o2) {
                int i = o1.getName().length() - o2.getName().length();

                //如果长度一样,比较内容
                int i1 = i == 0 ? o1.getName().compareTo(o2.getName()) : i;
                //姓名内容一样,年龄的大小不一定一样
                int i2 = i1 == 0 ? o1.getAge() - o2.getAge() : i1;
                return i2;
            }
        });


        //创建学生对象
        Student5 s1 = new Student5("mingwang", 18);
        Student5 s2 = new Student5("wangyu", 18);
        Student5 s3 = new Student5("zhoujiaxiang", 17);
        Student5 s4 = new Student5("zhangbaogui", 18);
        Student5 s5 = new Student5("liuzhicheng", 18);
        Student5 s6 = new Student5("wangyu", 20);

        //将学生对象添加到集合中
        set.add(s1);
        set.add(s2);
        set.add(s3);
        set.add(s4);
        set.add(s5);
        set.add(s6);

        for(Student5 Student5 : set){
            System.out.println(Student5);
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/734311.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号