看不懂源码? 来认识认识泛型

泛型

泛型类的定义

语法

class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}

了解: 【规范】类型形参一般使用一个大写字母表示,常用的名称有:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四个类型

简单示例

定义一个泛型类顺序表

// 演示泛型目的,没有做错误处理和扩容
public class MyArrayList<E> {
private E[] array;
private int size;
public MyArrayList() {
// 泛型类型无法直接创建数组,具体的见下面的注意事项
array = (E[])new Object[16];
size = 0;
}
// 尾插
public void add(E e) {
array[size++] = e;
}
// 尾删
public E remove() {
E element = array[size - 1];
array[size - 1] = null; // 将容器置空,保证对象被正确释放
size--;
return element;
}
}

加入静态内部类的示例

1.引入库

定义一个泛型类链表

public class MyLinkedList<E> {
public static class Node<E> {
private E value;
private Node<E> next;
private Node(E e) {
value = e;
next = null;
}
}
private Node<E> head;
private int size;
public MyLinkedList() {
head = null;
size = 0;
}
// 头插
public void pushFront(E e) {
Node<E> node = new Node<>(e);
node.next = head;
head = node;
size++;
}
// 尾插
public void pushBack(E e) {
if (size == 0) {
pushFront(e);
return;
}
Node<E> cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = new Node<E>(e);
size++;
}
}

加入继承或实现的示例
定义一个泛型类顺序表

public interface MyList<E> {
// 尾插
void add(E e);
// 尾删
E remove();
}
public class MyArrayList<E> implements MyList<E> {
// TODO: 未完成
}

泛型类的使用

语法
泛型类<类型实参> 变量名; // 定义一个泛型类引用
new 泛型类<类型实参>(构造方法实参); // 实例化一个泛型类对象
示例

MyArrayList list = new MyArrayList();

类型推导(Type Inference)
MyArrayList list = new MyArrayList<>(); // 可以推导出实例化需要的类型实参为 String

泛型类的定义-类型边界

在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。

语法

class 泛型类名称<类型形参 extends 类型边界> {
...
}

public class MyArrayList<E extends Number> {
...
}

只接受 Number 的子类型作为 E 的类型实参
MyArrayList l1; // 正常,因为 Integer 是 Number 的子类型

MyArrayList l2; // 编译错误,因为 String 不是 Number 的子类型
error: type argument String is not within bounds of type-variable E
MyArrayList l2;
^
where E is a type-variable:
E extends Number declared in class MyArrayList

类型擦除

class MyArrayList {
// E 会被擦除为 Object
}
class MyArrayList<E extends Comparable> {
// E 被擦除为 Comprable
}
我们之前已经讲过,泛型是作用在编译期间的一种机制,实际上运行期间是没有这么多类的,那运行期间是什么类
型呢?这里就是类型擦除在做的事情。

class MyArrayList<E> {
// E 会被擦除为 Object
}
class MyArrayList<E extends Comparable<E>> {
// E 被擦除为 Comprable
}

总结: 即类型擦除主要看其类型边界而定

泛型类的使用-通配符(Wildcards)

基本
? 用于在泛型的使用,即为通配符

public class MyArrayList<E> {...}
// 可以传入任意类型的 MyArrayList
public static void printAll(MyArrayList<?> list) {
...
}
// 以下调用都是正确的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Double>());
printAll(new MyArrayList<Number>());
printAll(new MyArrayList<Object>());

通配符-上界

? extends 上界

可以传入类型实参是 Number 子类的任意类型的 MyArrayList
public static void printAll(MyArrayList<? extends Number> list) {
}
// 以下调用都是正确的

printAll(new MyArrayList());

printAll(new MyArrayList());

printAll(new MyArrayList());

// 以下调用是编译错误的

printAll(new MyArrayList());

printAll(new MyArrayList());

通配符-下界

<? super 下界>

```java
// 可以传入类型实参是 Integer 父类的任意类型的 MyArrayList
public static void printAll(MyArrayList<? super Integer> list) {
、、、、…
}
// 以下调用都是正确的
printAll(new MyArrayList());
printAll(new MyArrayList());
printAll(new MyArrayList());
// 以下调用是编译错误的
printAll(new MyArrayList());
printAll(new MyArrayList()

泛型中的父子类型(重要)

public class MyArrayList<E> { ... }
// MyArrayList<Object> 不是 MyArrayList<Number> 的父类型
// MyArrayList<Number> 也不是 MyArrayList<Integer> 的父类型
// 需要使用通配符来确定父子类型
// MyArrayList<?> 是 MyArrayList<? extends Number> 的父类型
// MyArrayList<? extends Number> 是 MyArrayList<Integer> 的父类型

泛型方法

方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { …}.

public class Util {
public static <E> void swap(E[] array, int i, int j) {
E t = array[i];
array[i] = array[j];
array[j] = t;
}
}

泛型的限制

  1. 泛型类型参数不支持基本数据类型
  2. 无法实例化泛型类型的对象
  3. 无法使用泛型类型声明静态的属性
  4. 无法使用 instanceof 判断带类型参数的泛型类型
  5. 无法创建泛型类数组
  6. 无法 create、catch、throw 一个泛型类异常(异常不支持泛型)
  7. 泛型类型不是形参一部分,无法重载

完整定义一份泛型类支持的搜索树

import java.util.*;
public class BSTree<K extends Comparable<K>, V> {
private static class Entry<K, V> {
private K key;
private V value;
private Entry<K, V> left = null;
private Entry<K, V> right = null;
private Entry(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return String.format("{%s=%s}", key, value);
}
}
private Entry<K, V> root = null;
public V get(K key) {
Entry<K, V> cur = root;
while (cur != null) {
int r = key.compareTo(cur.key);
if (r == 0) {
return cur.value;
} else if (r < 0) {
cur = cur.left;
} else {
cur = cur.right;
}
}
return null;
}
public V put(K key, V value) {
if (root == null) {
root = new Entry<>(key, value);
return null;
}
Entry<K, V> parent = null;
Entry<K, V> cur = root;
while (cur != null) {
int r = key.compareTo(cur.key);
if (r == 0) {
V oldValue = cur.value;
cur.value = value;
return oldValue;
} else if (r < 0) {
parent = cur;
cur = cur.left;
} else {
parent = cur;
cur = cur.right;
}
}
Entry<K, V> entry = new Entry<>(key, value);
if (key.compareTo(parent.key) < 0) {
parent.left = entry;
} else {
parent.right = entry;
}
return null;
}
public V remove(K key) {
Entry<K, V> parent = null;
Entry<K, V> cur = root;
while (cur != null) {
int r = key.compareTo(cur.key);
if (r == 0) {
V oldValue = cur.value;
removeEntry(parent, cur);
return oldValue;
} else if (r < 0) {
parent = cur;
cur = cur.left;
} else {
parent = cur;
cur = cur.right;
}
}
return null;
}
private void removeEntry(Entry<K, V> parent, Entry<K, V> cur) {
if (cur.left == null) {
if (cur == root) {
root = cur.right;
} else if (cur == parent.left) {
parent.left = cur.right;
} else {
parent.right = cur.right;
}
} else if (cur.right == null) {
if (cur == root) {
root = cur.left;
} else if (cur == parent.left) {
parent.left = cur.left;
} else {
parent.right = cur.left;
}
} else {
Entry<K, V> gParent = cur;
Entry<K, V> goat = cur.left;
while (goat.right != null) {
gParent = goat;
goat = goat.right;
}
cur.key = goat.key;
cur.value = goat.value;
if (goat == gParent.left) {
gParent.left = goat.left;
} else {
gParent.right = goat.left;
}
}
}
public static interface Function<T> {
void apply(T entry);
}
public static <K, V> void preOrderTraversal(Entry<K, V> node, Function<Entry<K, V>>
func) {
if (node != null) {
func.apply(node);
preOrderTraversal(node.left, func);
preOrderTraversal(node.right, func);
}
}
public static <K, V> void inOrderTraversal(Entry<K, V> node, Function<Entry<K, V>>
func) {
if (node != null) {
inOrderTraversal(node.left, func);
func.apply(node);
inOrderTraversal(node.right, func);
}
}
public void print() {
System.out.println("前序遍历: ");
preOrderTraversal(root, (n) -> {
System.out.print(n.key + " ");
});
System.out.println();
System.out.println("中序遍历: ");
inOrderTraversal(root, (n) -> {
System.out.print(n.key + " ");
});
System.out.println();
}
public static void main(String[] args) {
BSTree<Integer, String> tree = new BSTree<>();
int count = 0;
Random random = new Random(20190915);
for (int i = 0; i < 20; i++) {
int key = random.nextInt(200);
String value = String.format("Value of %d", key);
if (tree.put(key, value) == null) {
count++;
}
}
System.out.println("一共插入 " + count + " 个结点");
tree.print();
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值