Better

业精于勤荒于嬉

Java 泛型

Better's Avatar 2019-06-27 Java

  1. 1. generic type and generic method
    1. 1.1. generic type
    2. 1.2. generic method
  2. 2. generics Inheritance subtypes
  3. 3. bounded type parameters
    1. 3.1. upper bound wildcards
    2. 3.2. lower bound wildcards
    3. 3.3. unbound wildcards
  4. 4. type ensure
    1. 4.1. generic type ensure
    2. 4.2. generic method ensure
    3. 4.3. tyepe ensure warning
  5. 5. Restriction on generic
  6. 6. 参考

泛型使得在定类、接口、方法时可以传递类型信息(类、接口)作为参数。

比起没有泛型的时期,使用泛型更方便于:

  • 编译期间类型安全检查,编译期间的错误比起运行时错误更方便解决

  • 避免了类型转换cast

  • 有助于抽象出针对同一类型的计算逻辑 generic algorithms

generic type and generic method

Java 中泛型使用<T> 符号申明在类、接口、方法处。

一般而言T符号的取值参考有:

  • E - Element (比如集合中使用)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types
1
2
class Box<T>{
}

Box 类需要使用一个泛型参数。是使用的时候需要申明具体的实参类型才行。

generic type

申明在类、接口处的泛型,在初始化类的时候,需要传递具体的参数类型。泛型类

1
2
3
4
5
class Box<T>{
void add(T t){}
}

Box<Intger> box = new Box<>()

generic method

声明在方法处的泛型,在调用方法的时候,需要传递具体的参数类型。与 generic type 不一样的是,这个是方法自己特有的泛型信息。泛型方法

1
2
3
4
5
6
7
class Utils{
public statistic <T> boolean compare (T t){}
    public <T> boolean compare2 (T t){}
}

Utils.<Integer>compare(2,3)
new Utils.<Integer>compare2(2,3)

generics Inheritance subtypes

IntegerNumber类的子类,但是Box<Integer>Box<Number>之间是没有继承关系。

泛型类或者接口是可以被extends或者impements。这样泛型类型之间就有用继承关系了。

ArrayList<String>List<String>的子类型 subtype

List<String>ArrayList<String>的父类型 supertype

bounded type parameters

泛型的赋值是任意类型的,但是也可以限定具体的类型。

1
2
3
public <U extends Number> void inspect(U u){
System.out.println("U: " + u.getClass().getName());
}

inspect()限定了只能用于Number类型或者Number类型的子类作为参数。

?在泛型中是一个比较常用的符号,用来表示某一类类型,未知类型。通常将?类型传递给申明处的泛型类型<T>来达到限制类型边界作用。

U extends Number以及? extends Number晃眼一看比较类似。

  • 前者是泛型在申明时,指定了泛型在初始化的边界信息。通常在泛型类或者泛型方法申明处使用。

  • 后者是泛型在调用时,指定了能支持的实际参数类型。通常是在方法申明参数的时候使用。

限定泛型的边界有助于实现generic algorithms

1
2
3
4
5
6
7
public static <T> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}

因为T是任意类型的,限定一下T的具体类型就可以实现泛型的比较了

1
2
3
4
5
6
7
8
9
10
11
public interface Comparable<T> {
public int compareTo(T o);
}

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}

upper bound wildcards

1
2
3
4
5
6
public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}

sumOfList() 方法接受的参数可以List<Integer>,List<Double>, 以及List<Number>都可以。

extends标记的变量只能提供提供元素get(),是一个in类型的变量。

lower bound wildcards

1
2
3
4
5
public static void addNumbers(List<? super Integer> list) {
for (int i = 1; i <= 10; i++) {
list.add(i);
}
}

addNumbers()限定了支持的参数有List<Integer>,List<Number>,以及List<Object>

super关键字标记的变量只能保存数据set(),是一个out变量。

unbound wildcards

1
public static void printList(List list) { double s = 0.0; for (Number n : list) s += n.doubleValue(); return s;}

printList()方法支持大于任何的List对象,并没有限制边界

type ensure

泛型类型在编译后,被抹除掉了,使用到泛型的地方,如果明显的指定了泛型的边界信息泛型类型将会被替换成边界类型信息,否者就是Object类型。

泛型类被抹除泛型信息后就是raw type。下面的Node<T>的raw tye 就是Node

generic type ensure

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Node<T> {

private T data;
private Node<T> next;

public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}

public T getData() { return data; }
// ...
}

泛型T是没有指定边界的,所以Java 编译器或有Object来代替它:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Node {

private Object data;
private Node next;

public Node(Object data, Node next) {
this.data = data;
this.next = next;
}

public Object getData() { return data; }
// ...
}

如果指定泛型边界

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Node<T extends Comparable<T>> {

private T data;
private Node<T> next;

public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}

public T getData() { return data; }
// ...
}

编译后:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Node {

private Comparable data;
private Node next;

public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}

public Comparable getData() { return data; }
// ...
}

generic method ensure

1
2
3
4
5
6
7
public static <T> int count(T[] anArray, T elem) {
int cnt = 0;
for (T e : anArray)
if (e.equals(elem))
++cnt;
return cnt;
}

T没有指定边界,所以用Object代替

1
2
3
4
5
6
7
public static int count(Object[] anArray, Object elem) {
int cnt = 0;
for (Object e : anArray)
if (e.equals(elem))
++cnt;
return cnt;
}

T指定了边界

1
2
3
4
class Shape { /* ... */ }
class Circle extends Shape { /* ... */ }
class Rectangle extends Shape { /* ... */ }
public static <T extends Shape> void draw(T shape) { /* ... */ }

tags: [Java反射,构造器,Constructors]
categories: Java译文编译后

1
public static void draw(Shape shape) { /* ... */ }

tyepe ensure warning

由于泛型信息被抹除了,下面的结果是true,被编译后两个List的class 信息都是Object,所以相等。

1
new ArrayList().getClass() == new ArrayList().getClass()

Restriction on generic

由于类型擦除,我们失去了获取形参T实际类型的能力,我们不能new T()、new T[]、List.class、instanceof List。

参考

Java tutorials generic

This article was last updated on days ago, and the information described in the article may have changed.