Java核心类库(上)

227 阅读17分钟

常用类

Object类

package cn.timevaeless.任务十常用类;

import java.util.Objects;

/**
 * Object类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/17 11:25 AM
 */
public class OObject extends Object {

    private String name;

    /**
     * equals方法要同时满足如下条件:
     * ①reflexive: x.equals(x) should return true
     * ②symmetric: x.equals(y) should return true, y.equals(x) returns true
     * ③transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true
     * ④consistent: multiple invocations of x.equals(y) consistently return true or consistently return false
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {

        // reflexive
        if (this == obj) {
            return true;
        }

        // 可比
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        OObject oobj = (OObject) obj;

        return name != null ? name.equals(oobj.name): oobj.name == null;

    }

    /**
     * hashcode方法要满足,当equals相等时,hashcode也需要相等,可以把hashcode理解为内存地址值。
     * If two objects are equal according to the equals(Object) method,
     * then calling the hashCode method on each of the two objects must produce the same integer result.
     * @return
     */
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    /**
     * toString
     * It is recommended that all subclasses override this method.
     * @return
     */
    @Override
    public String toString() {
        return "OObject{" +
                "name=" + name +
                '}';
    }
}

包装类

package cn.timevaeless.任务十常用类;

/**
 * 包装类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/17 12:36 PM
 */
public class Wrapper {

    // int num = 10,基本数据类型不是对象,而java是面向对象语言
    // 为了符合该理念,将基本数据类型包装为对象

    static class MyInt {
        private int num;

        public MyInt(int num) {
            this.num = num;
        }
    }

    public static void main(String[] args) {

        System.out.println(Integer.MAX_VALUE); // 2^31 - 1
        System.out.println(Integer.MIN_VALUE); // -2^31
        System.out.println(Integer.SIZE); // 所占位数
        System.out.println(Integer.BYTES); // 所占字节数
        System.out.println(Integer.TYPE); // int类型的Class实例名

        // 装箱:从int类型转换成Integer类型
        Integer integer = Integer.valueOf(10);
        // 自动装箱 (since(jdk5))
        integer = 10;
        // 拆箱:从Integer类型转换成int类型
        int i = integer.intValue();
        // 自动拆箱
        i = integer;

        // 自动装箱池:默认将-128-127的整数装箱完毕,当使用该范围内的整数时,无需装箱,直接取自动装箱池中的对象即可。
        Integer integer2 = 128;
        Integer integer3 = 128;
        Integer integer4 = 127;
        Integer integer5 = 127;
        Integer integer6 = new Integer(128);
        Integer integer7 = new Integer(128);

        System.out.println(integer2 == integer3); // false
        System.out.println(integer4 == integer5); // true
        System.out.println(integer6 == integer7); // false

        // 进制
        System.out.println(Integer.toBinaryString(200));
        System.out.println(Integer.toHexString(200));
        System.out.println(Integer.toOctalString(200));

        // Number类是Byte, Double, Float, Integer, Long, Short的共同抽象父类
        Number d = Double.valueOf("3.14");
        System.out.println(d);

        // Boolean
        System.out.println(Boolean.parseBoolean("TRUE"));

        // Character
        System.out.println(Character.getNumericValue('a')); // 10
        
    }
}

String类

/**
 * String类
 *
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/17 7:05 PM
 */
public class SString {

    public static void main(String[] args) {
        // 验证字符串常量池的存在
        String str = "abs";
        String str2 = "abs";
        System.out.println(str == str2);


        String s = new String(); // ""
        System.out.println("s = " + s);

        byte[] bytes = {'a', 98, 99, 'd'};

        // 使用字节数组构造字符串
        String s1 = new String(bytes, 0, bytes.length);
        System.out.println(s1);

        // 使用字符数组构造字符串
        char[] chars = {'h', 'e', 'l', 'l', 'o'};
        String s2 = new String(chars, 0, chars.length);
        System.out.println(s2);

        // 请问下面有几个对象? (2个,一个是字符串常量池中的abc对象,一个是堆中的)
        String abc = new String("abc");

        // 常量有优化机制,变量没有
        String abc1 = "abc";
        String abc2 = "ab" + "c";
        System.out.println(abc1 == abc2);

        String abc3 = "ab";
        String abc4 = abc3 + "c";
        System.out.println(abc1 == abc4);

        // String转换为byte数组
        // 先将字符串拆分为字符,再将字符转换为byte,也就是获取所有字符的ascii码。
        byte[] bytes1 = "abc北京欢迎你".getBytes();
        System.out.println(Arrays.toString(bytes1));

        char[] chars1 = "abc北京欢迎你".toCharArray();
        System.out.println(Arrays.toString(chars1));


        // 利用ascii码将字符串12345转换为整数12345
        String num = "12345";
        int b = 0;
        for (int i = 0; i < num.length(); i++) {
            b = b * 10 + num.charAt(i) - '0';
        }
        System.out.println(b);

        // 判断是否是回文
        String t = "上海自来水来自海上";
        int i;
        for (i = 0; i < t.length() / 2; i++) {
            if (t.charAt(i) != t.charAt(t.length() - 1 - i)) {
                break;
            }
        }
        if (i == t.length() / 2) {
            System.out.println("是回文");
        }

        // 字符串之间大小比较
        String str3 = "hello";
        String str4 = "haha"; // e - a = 4
        String str5 = "world"; // h - w = -15
        String str6 = "heihei"; // l - i = 3
        String str7 = "helloworld"; // -5 如果前面一样,则返回长度差 this.length()-anotherString.length()
        System.out.println(str3.compareTo(str4));
        System.out.println(str3.compareTo(str5));
        System.out.println(str3.compareTo(str6));
        System.out.println(str3.compareTo(str7));

        // 找到所有day的索引位置
        String str8 = "Day Day Up.";
        // 方法一
        int pos = str8.indexOf("Day");
        while (pos != -1) {
            System.out.print(pos + ", ");
            pos = str8.indexOf("Day", pos + 1);
        }
        // 方法二
        pos = 0;
        while ((pos = str8.indexOf("Day", pos)) != -1) {
            System.out.print(pos + ",");
            pos = pos + "Day".length();
        }

    }
}

正则表达式

/**
 * 正则表达式
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/17 10:41 PM
 */
public class RRegx {

    // [abc] - 可以出现a、b、c任意一个字符
    // [^abc] - 可以出现任意一个字符,除了a、b、c
    // [a-zA-Z0-9]

    // . - 任意一个字符,除了换行符
    // \d - 可以出现任意一个数字字符
    // \D - 可以出现任意一个非数字字符
    // \s - 空白字符,如\t、\n、\xOB(垂直制表符)、\f(换页符)、\r(回车不换行)
    // \S - 非空白字符
    // \w - 任意一个单词,相当于[a-zA-Z_0-9]
    // \W - 任意一个非单词字符

    // X? - 表示X可以出现0-1次
    // X* - 表示X可以出现0-n次
    // X+ - 表示X可以出现1-n次
    // X{n} - 表示X恰好出现n次
    // X{n, } - 表示X可以出现>=n次
    // X{n, m} - 表示X可以出现(n<=X<=m)次


    public static void main(String[] args) {

        // 判断用户是不是大于6位且首位必须是字母
        String regex = "[a-zA-Z]\\w{5,}";

        // 判断是不是QQ号
        String regex2 = "[1-9]\\d{4,14}";

        // 判断是不是手机号
        String regex3 = "1[3456789]\\d{9}";

        // 判断是不是身份证号
        String regex4 = "(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9|X|x])";

        String user = "_imevaeless";
        String qq = "342623";
        System.out.println(user.matches(regex));
        System.out.println(qq.matches(regex2));

        // Split
        String str = "001SACGHA002BY";
        String regex5 = "[G-Z]+";
        String[] strArray = str.split(regex5);
        for (String s : strArray) {
            System.out.println(Long.parseLong(s, 16));
        }

        // replace 替换所有
        String replace = str.replace('A', 'a');
        System.out.println(replace);

        // replaceFirst 可以使用正则
        System.out.println(str.replaceFirst("[A-Z]+", "A"));

        // replaceAll 可以使用正则
        System.out.println(str.replaceAll("[A-Z]+", "#"));
    }

}

StringBuilder类

/**
 * StringBuilder类
 *
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/18 8:48 AM
 */
public class SStringBuilder {

    // 由于String类描述的字符串内容是个常量不可改变
    // 当需要在Java代码中描述大量类似的字符串时,只能单独申请和存储,此时会造成内存空间的浪费。

    public static void main(String[] args) {

        StringBuilder sb = new StringBuilder(); // capacity = 16
        sb = new StringBuilder(32); // capacity = 32
        sb = new StringBuilder("Hello"); // capacity = 16 + "Hello".length

        System.out.println(sb.capacity()); // 21
        System.out.println(sb.length()); // 5
        System.out.println(sb.append("EFGABD") // HelloEFGABD
                .insert(sb.length() - 1, "C") // HelloEFGABCD  offset是插在该位置前面,因为insert(0,) 肯定插在最前面
                .deleteCharAt(sb.length() - 5) // HelloEFABCD
                .delete(sb.length() - 6, sb.length() - 4) // HelloABCD
                .replace(sb.length() - 4, sb.length(), "StringBuilder !") // Hello StringBuilder !  左闭右开
                );
        // StringBuilder为什么要返回this?为了连续调用

    }
}

日期类

/**
 * Date类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/18 9:24 AM
 */
public class DDate {

    public static void main(String[] args) throws ParseException {

        long currentTimeMillis = System.currentTimeMillis();
        System.out.println(currentTimeMillis); // 从197001010000起到现在的毫秒值

        // Date
        Date date = new Date();
        date = new Date(currentTimeMillis);
        long time = date.getTime(); // 从197001010000起到现在的毫秒值
        date.setTime(time);
        System.out.println(date);

        // SimpleDateFormat:Date展示的不符合我们的习惯
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(date));
        System.out.println(sdf.parse("2020-12-20 08:08:00"));

        // Calendar:Date只适合美国,Calendar更适合全球化
        Calendar calendar = Calendar.getInstance();
        calendar.set(2020, 12, 20, 8, 8, 00);

        calendar.set(Calendar.MONTH, 15);
        calendar.add(Calendar.HOUR, 30);
        date = calendar.getTime(); // 获得Date对象
        System.out.println(sdf.format(date));

        // 多态的使用场合
        // 通过方法的参数传递形成多态: draw(new Rect(1, 2, 3, 4));
        // 在方法体中直接使用多态的语法格式: Account acc = new FixedAccount();
        // 通过方法的返回值类型形成多态:Calender getInstance(){return new GregorianCalendar(zone, aLocale);}

        // JDK8新的日期类:Calendar使用麻烦,并且线程不安全
        System.out.println(LocalDate.now());
        System.out.println(LocalTime.now());
        System.out.println(LocalDateTime.now());
        // 自定义
        LocalDateTime localDateTime = LocalDateTime.of(2020, 12, 21, 8, 8, 0);
        System.out.println(localDateTime.getMonth().name()); // 返回枚举类型
        System.out.println(localDateTime.getMonthValue());
        System.out.println(localDateTime.getDayOfMonth());
        // 设置值: 和String一样,源对象不可变,每次都产生新的对象
        LocalDateTime localDateTime1 = localDateTime.withYear(2021).withMonth(Month.DECEMBER.getValue()).withDayOfMonth(8);
        System.out.println(localDateTime == localDateTime1); // false 不是同一个对象,每次调用with都会生成新的对象
        System.out.println(localDateTime1);
        // 加减
        LocalDateTime localDateTime2 = localDateTime1.plusDays(20).minusMonths(10);
        System.out.println(localDateTime2);

        // Instant: 获取当前系统的时间,并不是系统的默认时区,而是本初子午线的时间,东八区差8小时
        Instant now = Instant.now();
        OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8)); // 获取东八区系统时间
        System.out.println(offsetDateTime);
        System.out.println(offsetDateTime.toInstant().toEpochMilli()); // 获取197001010000到现在的毫秒值
        Instant instant = Instant.ofEpochMilli(1597717402192L);
        System.out.println(instant.atOffset(ZoneOffset.ofHours(8)));

        // DateTimeFormatter
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = dateTimeFormatter.format(localDateTime);
        System.out.println(format);
        System.out.println(dateTimeFormatter.parse(format));

    }
}

Collection接口

/**
 * Collection类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/18 10:40 AM
 */
public class CCollection {

    public static void main(String[] args) {

        // 当需要在Java程序中记录单个数据内容时,则声明一个变量。
        // 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组。
        // 当需要在Java程序中记录多个类型不同的数据内容时,则创建一个对象。
        // 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组。
        // 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合。
        // 接口的引用指向实现类对象,形成多态。

        Collection collection = new ArrayList();
        collection.add(1);
        collection.add(2.0);
        collection.add("Hello");
        collection.add(true);
        collection.add(collection); // 当成整体添加到原集合里
        collection.addAll(collection); // 将元素添加到原集合里
        System.out.println(collection); // [1, 2.0, Hello, true, (this Collection), 1, 2.0, Hello, true, (this Collection)]

        // 判断是否包含指定对象
        collection.contains(2.0); // true

        // 判断是否包含参数指定的所有对象
        Collection collection2 = new ArrayList();
        collection2.add(1);
        collection2.add(1);
        collection2.add(2.0);
        collection.contains(collection2); // false 判断整体是不是collection的一个元素
        collection.containsAll(collection2); // 判断每个元素是不是都在collection里

        // 交集: 保留当前集合中存在且参数集合中存在的所有对象
        collection.retainAll(collection2); // 当前集合发生改变返回true,否则返回false
        System.out.println(collection); // [1, 2.0, 1, 2.0] 会直接改变该集合本身

        // 从集合中删除对象
        collection.remove(1); // [2.0, 1, 2.0] 通过equals来删除相等的元素, 只删一次
        // collection.removeAll(collection2); // []

        // 其他方法
        collection.size();
        collection.isEmpty();
        collection.clear();
        // boolean equal = (o.getClass() == ArrayList.class) ? equalsArrayList((ArrayList<?>) o) : equalsRange((List<?>) o, 0, size)
        collection.equals(collection);
        Object[] objects = collection.toArray(); // 集合转数组
        Arrays.asList(objects); // 数组转集合

        // Iterator: java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
        // java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。
        collection.add(1);
        collection.add(2);
        collection.add(3);
        Iterator iterator = collection.iterator(); // 相当于指针,一开始指向最开头前面
        iterator.hasNext(); // true
        iterator.next(); // 1
        iterator.hasNext(); // true
        iterator.next(); // 2
        iterator.hasNext(); // true
        iterator.next(); // 3
        iterator.hasNext(); // false
        // iterator.next(); // NoSuchElementException

        // 使用迭代器遍历每个元素
        iterator = collection.iterator();
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        while (iterator.hasNext()) {
            Object next = iterator.next();
            if (! iterator.hasNext()) {
                sb.append(next).append("]");
            } else {
                sb.append(next).append(", ");
            }
        }
        System.out.println(sb.toString()); // [1, 2, 3]

        // 使用迭代器遍删除元素
        iterator = collection.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            if (next == Integer.valueOf(2)) {
                iterator.remove();
                // collection.remove(next);
                // 检测到在并发修改该对象时可能产生ConcurrentModificationException
                // 通常不允许一个线程修改Collection,而另一个线程对其进行迭代。
            }
        }
        System.out.println(collection); // [1, 3]

        // 使用断点
        for (Object o: collection) {
            System.out.println(o);
        }

        // List
        // java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序。
        // 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类。
        // 其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便。
        // 其中LinkedList类的底层是采用双向链表进行数据管理的,访问不方便,增删元素方便。
        // 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别,
        // ArrayList更适合于随机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻的情形下可以忽略这个差别。
        // 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(last in first out LIFO)。
        // 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低,以后开发中基本不用。

        // ArrayList
        // 用断点分析是如何进行扩容的
        // 1.5倍进行扩容的,int newCapacity = oldCapacity + (oldCapacity >> 1);
        ArrayList arrayList = new ArrayList();
        arrayList.add("Hello");
        arrayList.add(arrayList.size(), "World");
        arrayList.addAll(collection); // [Hello, World, 1, 3]

        Object o = arrayList.get(0);
        arrayList.indexOf("World"); // 1
        arrayList.lastIndexOf("World"); // 1
        Object sourceValue = arrayList.set(2, "!"); // [Hello, World, !, 3]

        List list = arrayList.subList(0, 2); ; // [Hello, World]
        list.remove(0); // subList和arrayList仍共用同一块内存空间,所以修改subList,arrayList也会改变
        System.out.println(list); // [World]
        System.out.println(arrayList); // [World, !, 3]

        for (int i=0; i<arrayList.size();) { // 依次删除每个元素
            arrayList.remove(0);
        }
        System.out.println(arrayList);


        // LinkedList
        // 用断点分析是怎么实现双向链表的(通过Node)
        Queue linkedList = new LinkedList();
        linkedList.add("World");

        // Stack类:继承自Vector,被Queue取代
        Stack stack = new Stack();
        stack.push("end");
        stack.push("middle");
        stack.push("top");
        stack.pop(); // top
        stack.pop(); // middle
        stack.pop(); // end
        // stack.pop(); // EmptyStackException
        // stack.peek(); // EmptyStackException 看一下栈顶的值
        stack.isEmpty(); // true

        // Vector类
        Vector vector = new Vector();
        vector.add("Hello");
        System.out.println(vector);

        // Queue类
        Queue queue = new LinkedList();
        queue.offer("Hello");
        queue.offer("Queue");
        queue.offer("!"); // [Hello, Queue, !]
        queue.peek(); // 队首 Hello
        Object poll = queue.poll();// 出队 [Queue, !]
    }
}

泛型

/**
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/20 1:01 AM
 */
public class Generic {

    // ①集合中为什么能存放任意类型的数据?是因为集合把所有对象都当成Object类型放入的。
    // 集合虽然支持放入不同的类型,但取数据的时候极容易发生数据类型转换异常。

    // 泛型就是指定数据类型,泛型只在编译时期有效,在运行时期不区分是什么类型
    // <E> 就好比形式参数,我们可以传入各种数据类型


    public static void main(String[] args) {

        Person person = new Person(); // 不使用泛型,所有元素保存为Object类
        Person<Boolean> person2 = new Person<>();
        person.setGender(true);

        Person.printArray(new String[] {"Hello", "Genenic"});

        // ④Student是Person子类,但是List<Student> 并不是List<Person>的子类
        List<Person> list = new ArrayList<>();
        List<Student> list2 = new ArrayList<>();
        // list2 = list; // 编译错误

        // ⑤通配符:那么List<Student>的父类是啥呢?
        // <?>: 无限制的通配符
        // <? extends E>
        // <? super E>
        List<?> list3 = list;
        // list3.add(new Person()); // 编译错误,不能存?(只能取,不能存)


        List<? extends Person> list4 = list;
        // 依然只能取不能存
        // 因为<? extends Person>只告诉了类型的上限,而没有给一个具体的类型
        // 违背了泛型的初衷:保证编译阶段数据类型一致,防止运行期间类型转换异常
        // list4.add("Hello");

        List<? super Student> list5 = list;
        // 可以存
        // 都传下限的数据类型一定不会报错,所以允许传
        // 但如果传父类,如果给传,则取出来的时候又会面临数据类型转换问题了,父到子可能转换错误
        list5.add(new Student());
        // list5.add(new Person());

        // 结论:PECS (Producer Extends,Consumer Super)
        // 生产者:只取数据用 ? extends E
        // 消费者:只存数据用 ? super E,如 boolean addAll(Collection<? extends E> c)



    }
}

class Person<E> {

    private E name;
    private E gender;

    public void setGender(E gender) {
        this.gender = gender;
    }

    // ③这不叫泛型方法, E只是占位符,必须等Person实例化后才能明确E是啥数据类型,所以该方法不能加static关键字
    public E getName() {
        return name;
    }

    // 泛型方法
    public static <T> T printArray(T[] arr) {

        for (T t : arr) {
            System.out.println(t);
        }

        return arr[0];
    }
}

class Student extends Person { // ②不保留父类的泛型

}

class Teacher<E> extends Person<E> { // 保留父类的泛型

}

class Man<K, V> extends Person<K> { // 保留父类的泛型,同时在子类增加一个泛型



}

Set集合

package cn.timevaeless.任务十一集合;

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

/**
 * Set类
 *
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/20 10:11 AM
 */
public class SSet {

    public static void main(String[] args) {

        // ①Set是Collection的子接口,与List接口平级。
        // 元素没有先后放入次序,且不允许重复。
        // HashSet  -> 哈希表
        // TreeSet  -> 红黑树
        // LinkedHashSet    -> 哈希表+双向链表,双向链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。

        // ②HashSet元素放入原理
        // - 获取元素的hashCode,再由(tab.length - 1) & hash计算出该元素在数组中的索引位置。
        // - 若数组该位置没有元素,则将该元素直接放到该位置。
        // p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))
        // - 若该位置有元素,则使用新元素与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
        // - 若新元素与已有元素的哈希值相同,则使用新元素调用equals方法与已有元素依次比较。
        // - 若相等则添加元素失败,否则将元素直接放入即可。

        // ③为什么要求重写equals方法后要重写hashCode方法呢?
        // 当两个元素调用equals方法相等时证明这两个元素相同,重写hashCode方法后保证这两个元
        // 素得到的哈希码值相同,由同一个哈希算法生成的索引位置相同,此时只需要与该索引位置已有元
        // 素比较即可,从而提高效率并避免重复元素的出现。
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("one");
        boolean one = hashSet.add("one"); // false
        hashSet.add("two");
        hashSet.add("three");
        hashSet.add("four");
        hashSet.add("five");
        hashSet.add("six");
        System.out.println(hashSet); // 无序 [six, four, one, two, three, five]

        // ④TreeSet
        // 二叉树主要指每个节点最多只有两个子节点的树形结构。
        // 满足以下3个特征的二叉树叫做有序二叉树。
        //  a.左子树中的任意节点元素都小于根节点元素值;
        //  b.右子树中的任意节点元素都大于根节点元素值;
        //  c.左子树和右子树的内部也遵守上述规则;
        //
        // TreeSet底层采用红黑树进行数据管理,红黑树是有序二叉树的一种实现,所以是有序的。
        // 当有新元素插入到TreeSet集合时,需要能够比较大小。
        //
        // 比较元素大小的规则有两种方式:
        //  a.让元素类实现java.lang.Comparable接口;
        //  b.构造TreeSet集合时传入java.util.Comparator接口;
        TreeSet<Person> treeSet = new TreeSet<>();
        treeSet.add(new Person(18, "a"));
        treeSet.add(new Person(33, "b"));
        treeSet.add(new Person(22, "c"));
        System.out.println(treeSet); // [Person{age=18, name='a'}, Person{age=33, name='b'}, Person{age=22, name='c'}]

        treeSet = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) { // o1是新增的,o2是已有的
                int i = o1.getAge() - o2.getAge();
                return i != 0 ? i: o1.getName().compareTo(o2.getName());
            }
        });
        treeSet.add(new Person(18, "a"));
        treeSet.add(new Person(33, "b"));
        treeSet.add(new Person(33, "b")); // 重复元素
        treeSet.add(new Person(22, "c"));
        System.out.println(treeSet); // [Person{age=18, name='a'}, Person{age=22, name='c'}, Person{age=33, name='b'}]

    }
}

class Person implements Comparable<Person> {

    private int age;
    private String name;

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public int compareTo(Person o) {
        // 先按名字排序,再按年龄排序
        int i = name.compareTo(o.getName());
        return i != 0 ? i : age - o.getAge();
    }

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

Map集合

/**
 * Map类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/20 10:55 AM
 */
public class MMap {

    public static void main(String[] args) {

        // ①java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
        // K - 此映射所维护的键(Key)的类型,相当于目录。
        // V - 映射值(Value)的类型,相当于内容。
        // key不允许重复的,而且一个key只能对应一个value。
        // HashMap -> 哈希表。
        // TreeMap -> 红黑树。
        // LinkedHashMap -> 哈希表+内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
        // Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作为key或者value的数值。
        // Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的。
        // Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能。
        // 经常用于根据key检索value的业务场景。

        // ②元素放入HashMap集合的原理
        // - 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。
        // - 若该位置没有元素,则将该键值对直接放入即可。
        // - 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
        // - 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较。
        // - 若相等则将对应的value修改,否则将键值对直接放入即可。
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("1", "one");
        hashMap.put("2", "two");
        hashMap.put("3", "three");
        String one = hashMap.put("1", "one2");// 重复的key,覆盖之前的
        System.out.println("原来的值:" + one);

        // ③HashMap相关的常量
        // - DEFAULT_INITIAL_CAPACITY : HashMap的默认容量是16。
        // - DEFAULT_LOAD_FACTOR:HashMap的默认加载因子是0.75。
        // - threshold:扩容的临界值,该数值为:容量*填充因子,也就是12。即当数组size大于12时则进行扩容。
        //   !!!扩容的目的是让元素尽可能分散在不同的下标,即让每个链表链的元素尽可能少,遍历的时候效率就更好。
        // - TREEIFY_THRESHOLD:若Bucket中链表长度大于该默认值则转化为红黑树存储,该数值是8。
        // - MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,该数值是64。

        String s = hashMap.get("1"); // one
        boolean b = hashMap.containsKey("1"); // true
        b = hashMap.containsValue("one");// 被覆盖了 false
        String remove = hashMap.remove("1"); // one2

        Set<String> set = hashMap.keySet(); // map不能直接迭代,因为没有实现Iterator接口
        for (String key : set) {
            System.out.println(key + ":" + hashMap.get(key));
        }

        Collection<String> values = hashMap.values();
        for (String value: values) {
            System.out.println(value);
        }

        Set<Map.Entry<String, String>> entries = hashMap.entrySet();
        for (Map.Entry<String, String> entry: entries) {
            System.out.println(entry);
        }
    }
}

Collections工具类

package cn.timevaeless.任务十一集合;

import java.util.*;

/**
 * Collections类
 * @author timevaeless
 * @version 1.0
 * @date 2020/8/20 11:29 AM
 */
public class CCollections {

    public static void main(String[] args) {

        List<Animal> animals = Arrays.asList(new Animal(20), new Animal(10), new Animal(30));

        Animal max = Collections.max(animals);// Animal{age=30}

        max = Collections.max(animals, new Comparator<Animal>() {
            @Override
            public int compare(Animal o1, Animal o2) {
                return o2.getAge() - o1.getAge();
            }
        }); // Animal{age=10}

        Collections.reverse(animals); // 不需要返回值 [Animal{age=30}, Animal{age=10}, Animal{age=20}]
        Collections.swap(animals, 0, 1); // [Animal{age=10}, Animal{age=30}, Animal{age=20}]
        Collections.sort(animals); // 根据其元素的自然顺序将指定列表按升序排序 [Animal{age=10}, Animal{age=30}, Animal{age=20}]
        Collections.sort(animals, new Comparator<Animal>() {
            @Override
            public int compare(Animal o1, Animal o2) {
                return o2.getAge() - o1.getAge();
            }
        });  // [Animal{age=30}, Animal{age=20}, Animal{age=10}]

        Collections.shuffle(animals); // 随机打乱 [Animal{age=20}, Animal{age=10}, Animal{age=30}]

        List<Animal> animals2 = new ArrayList<>(20);
        animals2.size(); // 0 只是分配了内存,但实际没存放元素
        animals2 = Arrays.asList(new Animal[3]);

        Collections.copy(animals2, animals); // [Animal{age=20}, Animal{age=10}, Animal{age=30}]
    }
}


class Animal implements Comparable<Animal> {

    private int age;

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

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(Animal o) {
        return age - o.age;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "age=" + age +
                '}';
    }
}