目录
1、什么是泛型
泛型是JDK1.5推出的新特性,java允许定义泛型类、泛型接口和泛型方法。Java API中的一些类和接口使用泛型进行了修改。Java 泛型的参数只可以代表类,不能代表个别对象。由于Java泛型的类型参数之实际类型在编译时会被消除,所以无法在运行时得知其类型参数的类型,而且无法直接使用基本值类型作为泛型类型参数。Java编译程序在编译泛型时会自动加入类型转换的编码,故运行速度不会因为使用泛型而加快。
2、自定义栈
通过ArrayList封装泛型,模拟栈是否存在,栈的空间大小,push():压栈,pop():出栈:回栈顶的值之后将栈顶元素进行删除。peek():返回栈顶报留栈元素
import java.util.ArrayList;
/**
* 自定义栈,支持泛型
*
* @param <T> 类型化参数,在使用过程中,传递一个具体的类型替代它
*/
public class GenericStack<T> {
private ArrayList<T> stack = new ArrayList<>();
public boolean isEmpty() {
return stack.isEmpty();
}
public int size() {
return stack.size();
}
public void push(T element) {
stack.add(element);
}
public T pop() {
return stack.remove(size() - 1);
}
public T peek() {
return stack.get(size() - 1);
}
}
3、泛型方法
public class GenericMethodDemo {
public static void main(String[] args ) {
Integer[] integers = {1, 2, 3, 4, 5};
String[] strings = {"London", "Paris", "New York", "Austin"};
GenericMethodDemo.<Integer>print(integers);//或者print(integers);
GenericMethodDemo.<String>print(strings);//或者print(strings);实际类型没有明确指定。编译器自动发现实际类型
}
public static <E> void print(E[] list) {
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
System.out.println();
}
}
4、通配泛型
?称为非受限通配(unbounded wildcard),它和? extends Object是一样的。
? extends T称为受限通配(bounded wildcard),表示T或者T的一个子类型。
? super T称为下限通配(lower-bounded wildcard),表示T或者T的一个父类型。
通配符,打印栈中的对象以及清空栈。<?>是一个通配符,表示任何一种对象类型。它等价于<? extends Object>。
5、消除泛型对泛型的限制
编译器可以使用泛型信息,但这些信息在运行时是不可用的。这被称为类型消除。
泛型是使用一种叫做类型消除(擦除)的方法来实现的。编译器使用泛型类型信息来编译代码,但是随后会消除它。因此,泛型信息在运行时是不可用的。这种方法可以使泛型代码向后兼容使用原始类型的遗留代码。
泛型存在于编译时。一旦编译器确认泛型类型是安全使用的,就会将它转换为原始类型。例如:编译器检查左边的代码里泛型是否被正确使用,然后将它翻译成右边的代码。
由于泛型类型在运行时被擦除,因此,对于如何使用泛型类型是有一些限制的。见(6、对泛型的限制)。
6、对泛型的限制
限制1:不能使用new T()
运行时泛型T是不可用的。
限制2:不能使用new T[]
可以通过创建一个Object的数组,然后将它的类型转换为T[]来规避这个限制,
E[] elements = (E[])new Object[capacity];
类型转换到E[]会导致一个免检的编译警告,因为编译器无法确保在运行时类型转换是否能成功,这种类型的编译警告是使用java泛型的不足之处,也是无法避免的。
使用泛型类型创建泛型数组也是不允许的。
GenericStack<String>[] stack = new GenericStack<String>[10];//错误的
可以修改为下面代码来规避,但是会有编译警告
GenericStack<String>[] stack = (GenericStack<String>[])new GenericStack [10];
限制3:在静态上下文中不允许类的参数是泛型类型
由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例所共享的。因此,在静态方法、数据域或者初始化的语句中,为类引用泛型类型参数是非法的。
限制4:异常类不能是泛型的
7、泛型矩阵类
对于所有矩阵,除了元素类型不同以外,它们的加法和乘法操作都是类似的。因此,可以设计一个父类,不管它们的元素类型是什么,该父类描述所有类型的矩阵共享的通用操作,还可以创建若干个适用于指定矩阵类型的子类。
import com.iweb.generic.exception.MatrixException;
/**
* 使用泛型来设计用于矩阵运算的类
* @param <T>
*/
public abstract class GenericMatrix<T extends Number> {
protected abstract T add(T num1, T num2);
protected abstract T multiply(T num1, T num2);
protected abstract T zero();
/**
* 矩阵加法
*/
public T[][] addMatrix(T[][] matrix1,T[][] matrix2){
if(matrix1.length != matrix2.length || matrix1[0].length != matrix2[0].length)
throw new MatrixException("两个矩阵的行列不相等,不能完成加法操作");
@SuppressWarnings("unchecked")
T[][] results = (T[][])new Number[matrix1.length][matrix1[0].length];
for(int i = 0; i < results.length;i++) {
for(int j = 0; j < results[i].length;j++) {
results[i][j] = add(matrix1[i][j], matrix2[i][j]);
}
}
return results;
}
/**
* 将泛型类型T[][]的两个矩阵进行相乘
*/
public T[][] multiplyMatrix(T[][] matrix1,T[][] matrix2){
if(matrix1[0].length != matrix2.length) {
throw new MatrixException("两个矩阵不符合乘法运算规则");
}
@SuppressWarnings("unchecked")
T[][] results = (T[][])new Number[matrix1.length][matrix2[0].length];
for(int i = 0; i < results.length; i++) {
for(int j = 0; j < results[0].length;j++) {
results[i][j] = zero();
for(int k = 0; k < matrix1[0].length;k++) {
results[i][j] = add(results[i][j],multiply( matrix1[i][k], matrix2[k][j]));
}
}
}
return results;
}
//显示矩阵、操作以及它们的结果
public static void printResult(Number[][] matrix1,Number[][] matrix2,Number[][] matrix3,char operator) {
for(int i = 0; i < matrix1.length; i++) {
for(int j = 0; j < matrix1[0].length; j++)
System.out.print(" " + matrix1[i][j]);
if(i == matrix1.length / 2)
System.out.print(" " + operator + " ");
else
System.out.print(" ");
for(int j = 0;j < matrix2[0].length; j++) {
System.out.print(" " + matrix2[i][j]);
}
if(i == matrix1.length / 2)
System.out.print(" = ");
else
System.out.print(" ");
for(int j = 0;j < matrix3[0].length; j++)
System.out.print(matrix3[i][j] + " ");
System.out.println();
}
System.out.println();
}
}