

Collection:是一个接口,包含了大部分容器常用的一些方法List:是一个接口,规范了 ArrayList 和 LinkedList 中要实现的方法ArrayList:实现了 List 接口,底层为动态类型顺序表LinkedList:实现了 List 接口,底层为双向链表Stack:底层是栈,栈是一种特殊的顺序表Queue:底层是队列,队列是一种特殊的顺序表Deque:是一个接口Set:集合,是一个接口,里面放置的是 K 模型HashSet:底层为哈希桶,查询的时间复杂度为 O(1) TreeSet:底层为红黑树,查询的时间复杂度为 O(logn),关于 key 有序Map:映射,里面存储的是 K-V 模型的键值对HashMap:底层为哈希桶,查询时间复杂度为 O(1) TreeMap:底层为红黑树,查询的时间复杂度为 O(logn),关于 key 有序在 Java 中,由于基本类型不是继承自 Object,为了在泛型代码中可以支持基本类型,Java 给每个基本类型都对应了一个包装类型,如下图所示:

所谓的装箱其实就是将基本数据类型转化为包装类,而拆箱就是将包装类转化为基本数据类型。
为了减少开发者的负担,java 提供了自动机制,即不需要强制类型转换!
public static void main(String[] args) {
Integer i = 10;
int j = i; // 自动装箱
System.out.println(i); // 输出 10
System.out.println(j); // 输出 10
int a = 20;
Integer b = a; // 自动拆箱
System.out.println(a); // 输出 20
System.out.println(b); // 输出 20
}public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false
Integer e = -128;
Integer f = -128;
System.out.println(e == f); // true
Integer g = -129;
Integer h = -129;
System.out.println(g == h); // false
}Java 对 Integer 类型在 [-128, 127] 之间的值进行了缓存,目的是优化内存和性能。
[-128, 127] 之间,会直接从缓存中返回同一个 Integer 对象(所以 == 比较结果为 true)Integer 对象(所以 == 比较结果为 false)这就有点像字符串常量池的原理!当然这个值是多少,是由设计者说了算的,我们只需要知道有这个机制在即可!
Java 基本数据类型的包装类型的大部分都用到了缓存机制来提升性能。
Byte、Short、Integer、Long 这 4 种包装类默认创建了数值 [-128,127] 的相应类型的缓存数据Character 创建了数值在 [0,127] 范围的缓存数据Boolean 直接返回 TRUE or FALSE泛型是一种程序设计中的重要特性,主要用来编写与类型无关的代码。
它的核心思想就是:编写一次代码,适用于多种类型,提高代码的复用性、可读性和类型安全性。
class MyClass<T> {
T a;
T[] b = (T[])new Object[10]; // 数组的初始化仍然需要Object来构造,并且进行强制类型转换
}
public class demo3 {
public static void main(String[] args) {
// 泛型类的实例化
MyClass<String> a = new MyClass<>(); // 后面尖括号可以忽略类型
MyClass<Integer> b = new MyClass<Integer>();
}
}🤖注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
public class demo {
// 在返回值之前声明一下<T>表示一个泛型T,然后在返回值和参数列表以及方法体中就能使用了!
public <T> void swap(T[] arr, int i, int j) {
T tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5};
System.out.println("交换前:" + arr[1] + " " + arr[3]);
demo d = new demo();
d.swap(arr, 1, 3);
System.out.println("交换后:" + arr[1] + " " + arr[3]);
}
}有时候我们想写更灵活的泛型,就会用到通配符 ?,表示匹配任何一种类型。
? extends T(上界)表示类型是 T 或 T 的子类。
List<? extends Number> nums = new ArrayList<Integer>();
? super T(下界)表示类型是 T 或 T 的父类。
List<? super Integer> ints = new ArrayList<Number>();
在模拟实现哈希表的时候,内部需要有一个节点数组,并且采用泛型,此时按下面格式定义会报错:
public Node<K, V>[] arr = new Node<K, V>[10]; // ❌编译错误这是因为 Java 的泛型是编译时生效的,但在运行时会被 "擦除",即泛型信息不会保留在字节码中。也就是说,运行时 JVM 看到的其实是 Node[],而不是 Node<K, V>[]。
所以只能退而求其次,创建一个原始类型的数组,再手动强转成泛型数组:
// 正确做法:
new Node[10] // 创建的是原始类型的数组
(Node<K, V>[]) ... // 强制转换为泛型数组
// 合并起来就是这样子:
public Node<K, V>[] arr = (Node<K, V>)new Node[];并且为了消除警告,可以加上 @SuppressWarnings("unchecked") 注解来表示你知道这个操作不安全,但你已经检查过了:
@SuppressWarnings("unchecked")
public Node<K, V>[] arr = (Node<K, V>[]) new Node[10];当然,现代的做法是使用集合类,而避免使用泛型数组,如下所示:
List<Node<K, V>> list = new ArrayList<>(); // 编译通过!原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。