JAVA基础知识总结(万字长文一文了解JAVA所有基础知识)(中)

文章目录

  • 前言
  • 前期回顾
  • 常用基础类
    • 包装类
    • Integer类
    • Character类
    • String类
    • StringBuilder类
    • Arrays类
    • 数的随机
  • 泛型和容器
    • 泛型
    • ArrayList容器
    • LinkedList
    • ArrayDeque
    • Map
    • HashSet
    • TreeMap和TreeSet
    • LinkedHashMap和LinkedHashSet
    • 优先队列
    • 抽象容器类
    • Collections类
    • 容器总结
  • 总结
  • 参考文献
  • 写在文末

前言

 这期是Java长文总结的中篇,主要总结Java中常用的类、泛型、容器相关知识。长文预警!!!

前期回顾

JAVA基础知识总结(万字长文一文了解JAVA所有基础知识)(上)


常用基础类

包装类

Java前期已经介绍过有8种基本类型,每种基本类型都有一个对应的包装类。包装类种有一个实例变量,它保存着基本类型的值。此外,类中还包括一些静态方法,静态变量和实例方法。我们看一下对应关系。
在这里插入图片描述
Java很多代码只能操作对象,像容器,所以我们需要对基本类型进行包装成类,可以方便对数据的操作。
1) 每个包装类都有一个静态方法valueOf()进行装包,同时也有实例方法xxxValue()进行拆包,我们通过类名进行访问,这个函数可以将基本类型转化为包装类,不过Java5以后引入了自动包装,以及拆包技术。

Integer a = Integer.valueOf(100);
int b = a.intValue();
//或者
Integer a = 100;
int b = a;
  1. 包装类一般会重写Object方法
boolean equals(Object obj)//判断当前对象和参数传入的对象是否相同
int hashCode()//hashCode返回一个对象的哈希值,对两个对象,如果equals方法返回true,则hashCode也必须一样,反之不要求
String toString()//返回对象的字符串表示

3)包装类一般实现Java API中的Comparable接口

public interface Comparable<T> {
    public int compareTo(T o);
}
  1. 包装类中除了Character外,每个包装类都有一个静态的valueOf(String)方法、静态的parseXXX(String)方法以及静态toString方法。
 Boolean b = Boolean.valueOf("true");
 Float f = Float.valueOf("123.45f");
 
 boolean b = Boolean.parseBoolean("true");
 double d = Double.parseDouble("123.45");
 
 System.out.println(Boolean.toString(true));
 System.out.println(Double.toString(123.45));

5)包装类中定义了一些静态变量,包括所有数值类型都定义了MAⅩ_VALUE和MIN_VALUE,Float和Double还定义了一些特殊数值,比如正无穷、负无穷、非数值等等

 public static final int    MIN_VALUE = 0x80000000;
 public static final int    MAX_VALUE = 0x7fffffff;
 public static final double POSITIVE_INFINITY = 1.0 / 0.0; //正无穷
 public static final double NEGATIVE_INFINITY = -1.0 / 0.0; //负无穷
 public static final double NaN = 0.0d / 0.0; //非数值

6)6种数值类型包装类有一个共同的父类Number。Number是一个抽象类,在其中定义了一些方法。通过这些方法,包装类实例可以返回任意的基本数值类型。

 byte byteValue()
 short shortValue()
 int intValue()
 long longValue()
 float floatValue()
 double doubleValue()
  1. 不可变性 所有的包装类都声明为了final,不能被继承,同时内部的基本类型都是私有的且声明为final,没有定义setter方法。

Integer类

  1. 位反转:将int当作二进制,左边的位和右边的位进行互换,reverse是按位进行互换, reverseBytes是按byte进行互换。
  2. 循环移位,以左移举例,最高2位移动到最低2位,其他位向左移动
  3. valueOf的实现是通过一种叫做享元模式的设计思路进行设计的,在Integer包装类中有私有静态内部类IntegerCache,里面有个cache变量(静态Integer数组)在静态初始化中就已经被初始化了,保存了-128~127共256个整数对应的Integer对象,当数值位于这个范围内,直接进行获取就行,只有不在范围内,才使用new创建对象,所以在创建包装类对象时,我们一般使用静态的valueOf方法。(仅做了解)
public static int reverse(int i)
public static int reverseBytes(int i)
public static int rotateLeft(int i, int distance)
public static int rotateRight(int i, int distance)

Character类

Character类在Unicode字符级别(而非char级别)封装了字符的各种操作,在上期我们介绍了Unicode,每个字符都有一个编号。
在Java内部使用UTF-16进行编码,对于常用字符集(BMP),使用两字节,而对于增补字符集则需要2个char,4个字节表示,一个表示高代理项,一个表示低代理项。我们可以使用int可以表示任意一个Unicode字符,低21位表示Unicode编号,高11位表示0。整数编号在Unicode称为代码点,表示一个Unicode字符,与之相对,还有一个代码单元表示一个char,是用于存储代码点的最小单位。通俗理解两者关系,也就是说如果是常用字符集(一个代码点)一个代码单元存储,但如果是增补字符集(一个代码点),需要两个代码单元(也就是一个代理对Surrogate Pair)存储。
我们看一下Character的静态方法。

  1. 检查code point和char
//判断一个int是不是一个有效的代码点,小于等于0x10FFFF的为有效,大于的为无效
public static boolean isValidCodePoint(int codePoint)
//判断一个int是不是BMP字符,小于等于0xFFFF的为BMP字符,大于的不是
public static boolean isBmpCodePoint(int codePoint)
//判断一个int是不是增补字符,0x010000~0X10FFFF为增补字符
public static boolean isSupplementaryCodePoint(int codePoint)
//判断char是否是高代理项,0xD800~0xDBFF为高代理项
public static boolean isHighSurrogate(char ch)
//判断char是否为低代理项,0xDC00~0xDFFF为低代理项
public static boolean isLowSurrogate(char ch)
//判断char是否为代理项, char为低代理项或高代理项,则返回true
public static boolean isSurrogate(char ch)
//判断两个字符high和low是否分别为高代理项和低代理项
public static boolean isSurrogatePair(char high, char low)
//判断一个代码点由几个char组成,增补字符返回2, BMP字符返回1
public static int charCount(int codePoint)
  1. 获取字符类型(general category);检查字符是否为数字;检查是否为字母(Letter)
public static int getType(int codePoint)//获取字符类型
public static int getType(char ch)//获取字符类型
public static boolean isDigit(int codePoint)//检查字符是否为数字
public static boolean isLetter(int codePoint)//检查是否为字母
  1. 字符转换
public static int toLowerCase(int codePoint)
public static int toUpperCase(int codePoint)

String类

  1. 字符串可以通过常量、new以及运算符+和+=来创建String变量。
String name = "Hello";
String name = new String("Hello")
String name +="Hello";
  1. String类包括很多方法,以方便操作字符串
public boolean isEmpty() //判断字符串是否为空
public int length() //获取字符串长度
public String substring(int beginIndex) //取子字符串
public String substring(int beginIndex, int endIndex) //取子字符串
public int indexOf(int ch) //查找字符,返回第一个找到的索引位置,没找到返回-1
public int indexOf(String str) //查找子串,返回第一个找到的索引位置,没找到返回-1
public int lastIndexOf(int ch) //从后面查找字符
public int lastIndexOf(String str) //从后面查找子字符串
public boolean contains(CharSequence s) //判断字符串中是否包含指定的字符序列
public boolean startsWith(String prefix) //判断字符串是否以给定子字符串开头
public boolean endsWith(String suffix) //判断字符串是否以给定子字符串结尾
public boolean equals(Object anObject) //与其他字符串比较,看内容是否相同
public boolean equalsIgnoreCase(String anotherString) //忽略大小写比较是否相同
public int compareTo(String anotherString) //比较字符串大小
public int compareToIgnoreCase(String str) //忽略大小写比较
public String toUpperCase() //所有字符转换为大写字符,返回新字符串,原字符串不变
public String toLowerCase() //所有字符转换为小写字符,返回新字符串,原字符串不变
public String concat(String str) //字符串连接,返回当前字符串和参数字符串合并结果
public String replace(char oldChar, char newChar) //字符串替换,替换单个字符
public String replace(CharSequence target, CharSequence replacement)//字符串替换,替换字符序列,返回新字符串,原字符串不变
public String trim() //删掉开头和结尾的空格,返回新字符串,原字符串不变
public String[] split(String regex) //分隔字符串,返回分隔后的子字符串数组
public char charAt(int index) //返回指定索引位置的char
//返回字符串对应的char数组, 注意,返回的是一个复制后的数组,而不是原数组
public char[] toCharArray()
//将char数组中指定范围的字符复制入目标数组指定位置
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
  1. String类跟包装类类似,被声明位final,是不可变类,不能被继承。所以String的concat()方法原来的String对象不会被修改,而是新创建了一个对象。
  2. Java中的字符串常量,可以直接调用String的各种方法,本质上,这些常量就是String类型的对象,被放在一个共享的地方(字符串常量池),它保存所有的常量字符串,每个常量只会保存一份,被所有使用者共享。**当通过常量的形式使用一个字符串的时候,使用的就是常量池中的那个对应的String类型的对象。**我们可以做个对比,
# 1
String name1 = "Hello";
String name2 = "Hello";
System.out.println(name1==name2);
# 2
String name1 = new String("Hello");
String name2 = new String("Hellp")
System.out.println(name1==name2);

第1种为True,第2种为False。

StringBuilder类

  1. 如果对字符串修改操作比较频繁的话,我们会使用StringBuilder和StringBuffer,因为String是不可变的,每次修改都需要new一个新的对象,而StringBuilder维护的是一个可变的字符数组,可以直接修改。StringBuilder和StringBuffer区别在于StringBuilder是非线程安全的,如果在单线程情况下我们使用StringBuilder。
  2. 使用方法,通过append方法添加字符串,通过toString方法获取构建后的字符串。
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" World");
String result = sb.toString();
System.out.println(result);
  1. 常用函数:
public StringBuilder insert(int offset, String str)//在指定索引offset处插入字符串str

Arrays类

  1. toString
    Arrays的toString()方法可以将数组直接输出字符串形式。如果不使用这个方法,直接输出数组本身,将会输出内存地址等信息,难以阅读。
public static String toString(int[] a)
public static String toString(Object[] a)

2)排序sort,sort可以排序基本类型,还可以排序对象类型,除了基本类型,但对象需要实现Comparable接口。

public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
}
public static void sort(int[] a)
public static void sort(double[] a)

如果需要从大到小排序,对应对象类型,可以指定一个不同的Comparator,可以使用匿名内部类来实现。

String[] arr = {"hello", "world", "Break", "abc"};
Arrays.sort(arr, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o2.compareToIgnoreCase(o1);
    }
});
System.out.println(Arrays.toString(arr));
  1. 查找
    二分查找既可以针对基本类型数组,也可以针对对象数组,对于对象数组,需要传递Comparator。
public static int binarySearch(int[] a, int key)
public static int binarySearch(int[] a, int fromIndex, int toIndex, int key)
public static int binarySearch(Object[] a, Object key)//对象数组
  1. 判断两个数组是否相同
public static boolean equals(boolean[] a, boolean[] a2)
public static boolean equals(Object[] a, Object[] a2)
  1. 复制一个新数组
 public static long[] copyOf(long[] original, int newLength)
 public static <T> T[] copyOf(T[] original, int newLength)
  1. 给数组每个元素设置相同的值
public static void fill(int[] a, int val)
public static void fill(int[] a, int fromIndex, int toIndex, int val)
  1. 如果是多维数组,我们需要在方法前面加上deep。
int[][] arr = new int[][]{{0,1}, {2,3,4}, {5,6,7,8}};
System.out.println(Arrays.deepToString(arr));

数的随机

  1. Math.random输出的是0 ~ 1之间的随机数,类型为double
System.out.println(Math.random());

2)Random类
需要创建出一个对象,有以下方法:

Random rnd = new Random();
System.out.println(rnd.nextInt());//产生一个随机的int
System.out.println(rnd.nextInt(100));//产生一个随机int,范围是0~100
public long nextLong() //随机生成一个long
public boolean nextBoolean() //随机生成一个boolean
public void nextBytes(byte[] bytes) //产生随机字节, 字节个数就是bytes的长度
public float nextFloat() //随机浮点数,从0到1,包括0不包括1
public double nextDouble() //随机浮点数,从0到1,包括0不包括1

泛型和容器

泛型

  1. 泛型,通俗来讲,就是广泛的类型,同一套代码可以支持不同的数据类型。在类名后面加上,T表示类型参数,可以支持不同类型,使用方法,在创建对象的时候加上具体类型如
public class Pair<T> {
    T first;
    T second;
    public Pair(T first, T second){
        this.first = first;
        this.second = second;
    }
    public T getFirst() {
        return first;
    }
    public T getSecond() {
        return second;
    }
}
Pair<Integer> minmax = new Pair<Integer>(1,100);
Integer min = minmax.getFirst();
Integer max = minmax.getSecond();
  1. 泛型也可以支持不同类型,<U,V>,泛型的本质是Java编译器和JVM将其全部转化为Object类型,再进行强制类型转化,这种称为类型擦除
  2. 通过泛型,我们可以实现各种容器类。
  3. 泛型不仅可以支持类,也可以支持方法的泛型,在返回值前面放参数T。同样也支持多个类型。
public static <T> int indexOf(T[] arr, T elm){
    for(int i=0; i<arr.length; i++){
        if(arr[i].equals(elm)){
            return i;
        }
    }
    return -1;
}
  1. 泛型接口,接口也是可以泛型的,在实现接口时,指定具体的类型。
public interface Comparable<T> {
    public int compareTo(T o);
}
public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
}

6)如果我们需要对类型参数进行限界,就是传递的类型参数必须为给定的上界类型或子类型,这个限定我们可以通过extends实现。下面例子限定两个类型参数必须为Number。
7) 限定我们也可以通过通配符来实现。
无限定通配符(?):表示未知类型。
上界通配符(? extends T):表示类型必须是 T 或者 T 的子类。
下界通配符(? super T):表示类型必须是 T 或者 T 的父类。

public class NumberPair<U extends Number, V extends Number>
     extends Pair<U, V> {
     public NumberPair(U first, V second) {
         super(first, second);
     }
 }
  1. 不能创建泛型数组。

ArrayList容器

1)ArrayList是一个泛型容器。主要使用方法:

ArrayList<Integer> intList = new ArrayList<Integer>();
ArrayList<String> strList = new ArrayList<String>();
public boolean add(E e) //添加元素到末尾
public boolean isEmpty() //判断是否为空
public int size() //获取长度
public E get(int index) //访问指定位置的元素
public int indexOf(Object o) //查找元素, 如果找到,返回索引位置,否则返回-1
public int lastIndexOf(Object o) //从后往前找
public boolean contains(Object o) //是否包含指定元素,依据是equals方法的返回值
public E remove(int index) //删除指定位置的元素, 返回值为被删对象
public boolean remove(Object o)//删除指定对象,只删除第一个相同的对象,返回值表示是否删除了元素//如果o为null,则删除值为null的元素
public void clear() //删除所有元素
public void add(int index, E element)//在指定位置插入元素,index为0表示插入最前面,index为ArrayList的长度表示插到最后面
public E set(int index, E element) //修改指定位置的元素内容

我们可以通过foreach进行访问。
原理实现:通过实现Iterable接口,接口内实现iterator方法。

ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(123);
intList.add(456);
intList.add(789);
for(Integer a : intList){
    System.out.println(a);
}

特点:插入和删除元素的效率比较低,因为需要移动元素,具体为O(N)。

LinkedList

ArrayList随机访问效率很高,但插入和删除性能比较低;LinkedList与ArrayList用法类似,支持List接口,只是,LinkedList增加了一个接口Deque,我们可以把它看作队列、栈、双端队列,方便地在两端进行操作。LinkedList的本质是使用了双向链表。

//初始构造方法
public LinkedList()
public LinkedList(Collection<? extends E> c)
List<String> list = new LinkedList<String>();
//插入元素
list.add("a");
list.add("b");
//根据索引访问元素get
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}
//删除元素
public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}
//实现队列接口Queue
public interface Queue<E> extends Collection<E> {
    boolean add(E e);
    boolean offer(E e);
    E remove();
    E poll();
    E element();
    E peek();
}
//把LinkedList当作Queue使用
Queue<String> queue = new LinkedList<>();
queue.offer("a");
queue.offer("b");
queue.offer("c");
while(queue.peek()! =null){
    System.out.println(queue.poll());
}
//把LinkedList当作栈使用
Deque<String> stack = new LinkedList<>();
stack.push("a");
stack.push("b");
stack.push("c");
while(stack.peek()! =null){
    System.out.println(stack.pop());
}
//把LinkedList当作双端队列使用
 Deque<String> deque = new LinkedList<>(
         Arrays.asList(new String[]{"a", "b", "c"}));
 Iterator<String> it = deque.descendingIterator();
 while(it.hasNext()){
     System.out.print(it.next()+" ");
 }

ArrayDeque

ArrayDeque实现了双端队列,内部使用循环数组实现。
1)在两端添加、删除元素的效率很高
2)根据元素内容查找和删除的效率比较低,为O(N)
3) 与ArrayList和LinkedList不同,没有索引位置的概念,不能根据索引位置进行操作

//构造方法
public ArrayDeque()
public ArrayDeque(int numElements)
public ArrayDeque(Collection<? extends E> c)
//尾部添加
public boolean add(E e) {
    addLast(e);
    return true;
}
//头部添加
public void addFirst(E e) {
    if(e == null)
        throw new NullPointerException();
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if(head == tail)
        doubleCapacity();
}
//从头部删除
public E removeFirst() {
    E x = pollFirst();
    if(x == null)
        throw new NoSuchElementException();
    return x;
}
//查看长度
public int size() {
    return (tail - head) & (elements.length - 1);
}
//检查给定元素是否存在
 public boolean contains(Object o) {
     if(o == null)
         return false;
     int mask = elements.length - 1;
     int i = head;
     E x;
     while( (x = elements[i]) ! = null) {
         if(o.equals(x))
             return true;
         i = (i + 1) & mask;
     }
     return false;
 }
 //toArray方法
public Object[] toArray() {
   return copyElements(new Object[size()]);
}

Map

HashMap由Hash和Map两个单词组成,这里Map不是地图的意思,而是表示映射关系,是一个接口,实现Map接口有多种方式,HashMap实现的方式利用了哈希(Hash)。我们看一下Map接口的API

public interface Map<K, V> { //K和V是类型参数,分别表示键(Key)和值(Value)的类型
    V put(K key, V value); //保存键值对,如果原来有key,覆盖,返回原来的值
    V get(Object key); //根据键获取值, 没找到,返回null
    V remove(Object key); //根据键删除键值对, 返回key原来的值,如果不存在,返回null
    int size(); //查看Map中键值对的个数
    boolean isEmpty(); //是否为空
    boolean containsKey(Object key); //查看是否包含某个键
    boolean containsValue(Object value); //查看是否包含某个值
    void putAll(Map<? extends K, ? extends V> m); //保存m中的所有键值对到当前Map
    void clear(); //清空Map中所有键值对
    Set<K> keySet(); //获取Map中键的集合
    Collection<V> values(); //获取Map中所有值的集合
    Set<Map.Entry<K, V>> entrySet(); //获取Map中的所有键值对
    interface Entry<K, V> { //嵌套接口,表示一条键值对
        K getKey(); //键值对的键
        V getValue(); //键值对的值
        V setValue(V value);
        boolean equals(Object o);
        int hashCode();
    }
    boolean equals(Object o);
    int hashCode();
}
boolean containsValue(Object value);
Set<K> keySet();

我们看一下常见用例:

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建一个 HashMap 对象
        HashMap<String, Integer> map = new HashMap<>();

        // 插入键值对
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("cherry", 3);

        // 获取指定键对应的值
        int value = map.get("banana");
        System.out.println("Value of banana: " + value);

        // 检查是否包含指定的键
        boolean containsKey = map.containsKey("apple");
        System.out.println("Contains key 'apple': " + containsKey);

        // 检查是否包含指定的值
        boolean containsValue = map.containsValue(3);
        System.out.println("Contains value 3: " + containsValue);

        // 获取键值对的数量
        int size = map.size();
        System.out.println("Size of the map: " + size);

        // 遍历 HashMap
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        // 删除指定键的键值对
        map.remove("cherry");
        System.out.println("After removing 'cherry': " + map);
    }
}

PS: 1 HashMap不是线程安全的 2 HashMap中的键值对没有顺序,因为hash值是随机的

HashSet

HashMap与HashMap类似,字面上看,HashSet由两个单词组成:Hash和Set。其中,Set表示接口,实现Set接口也有多种方式,各有特点,Hash-Set实现的方式利用了Hash。Set表示的是没有重复元素、且不保证顺序的容器接口,它扩展了Collection,但没有定义任何新的方法,不过,对于其中的一些方法,它有自己的规范。
HashSet 内部使用 HashMap 来存储元素,HashSet 中的元素被作为 HashMap 的键,而 HashMap 的值则是一个固定的静态对象 PRESENT。当向 HashSet 中添加元素时,实际上是将该元素作为键存储到 HashMap 中,值为 PRESENT。通过 HashMap 的哈希机制,HashSet 可以快速判断元素是否已经存在于集合中。
Set接口的完整定义如下:

public interface Set<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    //迭代遍历时,不要求元素之间有特别的顺序
    //HashSet的实现就是没有顺序,但有的Set实现可能会有特定的顺序,比如TreeSet
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    //添加元素, 如果集合中已经存在相同元素了,则不会改变集合,直接返回false,
    //只有不存在时,才会添加,并返回true
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<? > c);
    //重复的元素不添加,不重复的添加,如果集合有变化,返回true,没变化返回false
    boolean addAll(Collection<? extends E> c);
    boolean retainAll(Collection<? > c);
    boolean removeAll(Collection<? > c);
    void clear();
    boolean equals(Object o);
    int hashCode();
}

与HashMap类似,HashSet要求元素重写hashCode和equals方法,且对于两个对象,如果equals相同,则hashCode也必须相同。我们看一下它的一些示例:

import java.util.HashSet;
public class HashSetExample {
    public static void main(String[] args) {
        // 创建一个 HashSet 对象
        HashSet<String> set = new HashSet<>();
        // 添加元素
        set.add("apple");
        set.add("banana");
        set.add("cherry");
        // 检查集合是否包含指定元素
        boolean contains = set.contains("banana");
        System.out.println("Set contains 'banana': " + contains);
        // 获取集合的大小
        int size = set.size();
        System.out.println("Size of the set: " + size);
        // 遍历 HashSet
        for (String element : set) {
            System.out.println(element);
        }
        // 删除指定元素
        set.remove("cherry");
        System.out.println("After removing 'cherry': " + set);
        // 检查集合是否为空
        boolean isEmpty = set.isEmpty();
        System.out.println("Is the set empty? " + isEmpty);
    }
}

特点:
1)没有重复元素;
2)可以高效地添加、删除元素、判断元素是否存在,效率都为O(1)
3)没有顺序
HashSet可以方便高效地实现去重、集合运算等功能。

TreeMap和TreeSet

相较于HashMap和HashSet通过哈希实现,TreeMap和TreeSet通过排序二叉树(红黑树)实现,键值对之间按键有序。TreeMap是按键有序的,默认从小到大,可以通过传比较器对象进行修改。举例:

Map<String, String> map   = new TreeMap<>(new Comparator<String>(){
	@Override
	public int compare(String o1, String o2) {
	    return o2.compareTo(o1);
	}
});
//或者Collections类有一个静态方法reverseOrder()可以返回一个逆序比较器
Map<String, String> map   = new TreeMap<>(Collections.reverseOrder());

其他我就不多累述了,跟HashMap主要区别就是键值是否有序。

LinkedHashMap和LinkedHashSet

LinkedHashMap是HashMap的子类,但可以保持元素按插入或访问有序(内部有一个双向链表以维护节点的顺序),这与TreeMap按键排序不同。LinkedHashSet是HashSet的子类,它内部的Map的实现类是LinkedHashMap,所以它也可以保持插入顺序,这里我们只看LinkedHashMap。

 Map<String, Integer> seqMap = new LinkedHashMap<>();
 seqMap.put("c", 100);
 seqMap.put("d", 200);
 seqMap.put("a", 500);
 seqMap.put("d", 300);
 for(Entry<String, Integer> entry : seqMap.entrySet()){
     System.out.println(entry.getKey()+" "+entry.getValue());
 }
 //输出
c 100
d 300
a 500

我们可以看到按照插入顺序输出。

优先队列

PriorityQueue。顾名思义,PriorityQueue是优先级队列,它首先实现了队列接口(Queue)​,与LinkedList类似,它的队列长度也没有限制,与一般队列的区别是,它有优先级的概念,每个元素都有优先级,队头的元素永远都是优先级最高的。PriorityQueue内部是用堆实现的,内部元素不是完全有序的,不过,逐个出队会得到有序的输出。

//实现Queue接口
public interface Queue<E> extends Collection<E> {
   boolean add(E e); //在尾部添加元素,队列满时抛异常
   boolean offer(E e); //在尾部添加元素,队列满时返回false
   E remove(); //删除头部元素,队列空时抛异常
   E poll(); //删除头部元素,队列空时返回null
   E element(); //查看头部元素,队列空时抛异常
   E peek(); //查看头部元素,队列空时返回null
}
//基础示例
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(10);
pq.add(22);
pq.addAll(Arrays.asList(new Integer[]{11, 12, 34, 2, 7, 4, 15, 12, 8, 6, 19, 13 }));
while(pq.peek()! =null){
   System.out.print(pq.poll() + " ");
}
//输出       
2 4 6 7 8 10 11 12 12 13 15 19 22 34

抽象容器类

虚线框表示接口,有Collection、List、Set、Queue、Deque和Map。
有6个抽象容器类。
1)AbstractCollection:实现了Collection接口,被抽象类AbstractList、AbstractSet、AbstractQueue继承。
2)AbstractList:实现了List接口,被ArrayList、Abstract-SequentialList继承。
3)AbstractSequentialList:父类是AbstractList,被LinkedList继承。
4)AbstractMap:实现了Map接口,被TreeMap、HashMap、EnumMap继承。
5)AbstractSet:父类是AbstractCollection,实现了Set接口,被HashSet、TreeSet和EnumSet继承。
6)AbstractQueue:父类是AbstractCollection,实现了Queue接口,被PriorityQueue继承。
在这里插入图片描述

Collections类

类Collections以静态方法的方式提供了很多通用算法和功能。第一类操作是一些通用算法,包括查找、替换、排序、调整顺序、添加、修改等,这些算法操作的都是容器接口对象,这是面向接口编程的一种体现,只要对象实现了这些接口,就可以使用这些算法。第二类操作都返回一个容器接口对象,这些方法代表两种设计模式,一种是适配器,另一种是装饰器。
1)二分查找
2)查找最大值/最小值
3)排序、交换位置与翻转
4)随机化重排
5)循环移位
6)添加和修改
7)适配器
8)装饰器

容器总结

容器类有两个根接口,分别是Collection和Map, Collection表示单个元素的集合,Map表示键值对的集合。Collection表示的数据集合有基本的增、删、查、遍历等方法,但没有定义元素间的顺序或位置,也没有规定是否有重复元素。List是Collection的子接口,表示有顺序或位置的数据集合,增加了根据索引位置进行操作的方法。Set也是Collection的子接口,它没有增加新的方法,但保证不含重复元素。Queue是Collection的子接口,表示先进先出的队列,在尾部添加,从头部查看或删除。Map接口表示键值对集合,经常根据键进行操作,它有两个主要的实现类:HashMap和TreeMap。HashMap还有一个子类LinkedHashMap,它可以按插入或访问有序。

总结

本篇文章总结了类、泛型、容器内容,下篇继续总结。

参考文献

Java编程的逻辑 马俊昌

写在文末

 如果想要更深入学习Java的友友,关注我,下期更精彩

请大家一定一定要关注!!!
请大家一定一定要关注!!!
请大家一定一定要关注!!!
友友们,你们的支持是我持续更新的动力~

创作不易,求关注,点赞,收藏,谢谢~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxchyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值